| 1 |
|
|---|
| 2 | /*
|
|---|
| 3 | *@@sourcefile textview.c:
|
|---|
| 4 | * all-new XTextView control as well as device-independent
|
|---|
| 5 | * text formatting and printing. Whoa.
|
|---|
| 6 | *
|
|---|
| 7 | * <B>Text view control</B>
|
|---|
| 8 | *
|
|---|
| 9 | * This is a read-only control to display any given text
|
|---|
| 10 | * (PSZ) in any given font. As opposed to a multi-line entry
|
|---|
| 11 | * field (MLE), this can handle multiple fonts and character
|
|---|
| 12 | * and paragraph formatting. Also, this thing sets its scroll
|
|---|
| 13 | * bars right, which is one of the most annoying bugs in the
|
|---|
| 14 | * MLE control.
|
|---|
| 15 | *
|
|---|
| 16 | * This is currently in the process of turning into a full-fledged
|
|---|
| 17 | * "rich text" control. For example, the WarpIN "Readme" pages
|
|---|
| 18 | * use this control.
|
|---|
| 19 | *
|
|---|
| 20 | * This is all new with V0.9.1. Great changes have been made
|
|---|
| 21 | * with V0.9.3.
|
|---|
| 22 | *
|
|---|
| 23 | * To use the text view control, you must call txvRegisterTextView
|
|---|
| 24 | * in your application first. This registers the WC_XTEXTVIEW
|
|---|
| 25 | * window class with PM.
|
|---|
| 26 | *
|
|---|
| 27 | * Then create your XTextView using WinCreateWindow. The
|
|---|
| 28 | * XTextView control has an XTEXTVIEWCDATA control data
|
|---|
| 29 | * structure which optionally can be passed to WinCreateWindow
|
|---|
| 30 | * like this:
|
|---|
| 31 | *
|
|---|
| 32 | + XTEXTVIEWCDATA xtxvCData;
|
|---|
| 33 | + memset(&xtxvCData, 0, sizeof(xtxvCData));
|
|---|
| 34 | + xtxvCData.cbData = sizeof(xtxvCData);
|
|---|
| 35 | + xtxvCData.flStyle = XTXF_VSCROLL;
|
|---|
| 36 | + xtxvCData.ulXBorder = 20;
|
|---|
| 37 | + xtxvCData.ulYBorder = 20;
|
|---|
| 38 | + G_hwndProcView = WinCreateWindow(hwndClient, // parent
|
|---|
| 39 | + WC_XTEXTVIEW, // class
|
|---|
| 40 | + "", // title, always ignored
|
|---|
| 41 | + WS_VISIBLE, // style flags
|
|---|
| 42 | + 0, 0, 100, 100, // pos and size
|
|---|
| 43 | + hwndClient, // owner
|
|---|
| 44 | + HWND_TOP, // z-order
|
|---|
| 45 | + ID_PROCINFO, // win ID
|
|---|
| 46 | + &xtxvCData, // control data
|
|---|
| 47 | + 0); // presparams
|
|---|
| 48 | +
|
|---|
| 49 | * <B>Setting the text to be displayed</B>
|
|---|
| 50 | *
|
|---|
| 51 | * The text to be displayed must be passed to the control using
|
|---|
| 52 | * the standard WinSetWindowText function (upon which PM sends a
|
|---|
| 53 | * WM_SETWINDOWPARMS message to the control), which is then
|
|---|
| 54 | * automatically formatted and painted.
|
|---|
| 55 | *
|
|---|
| 56 | * However, since the XTextView control is extremely capable,
|
|---|
| 57 | * a few things need to be noted:
|
|---|
| 58 | *
|
|---|
| 59 | * -- The text view assumes that lines terminate with \n ONLY.
|
|---|
| 60 | * The \r char is used for soft line breaks (start new line
|
|---|
| 61 | * in the same paragraph, similar to the HTML BR tag). If
|
|---|
| 62 | * you give the control the usual OS/2 \r\n sequence, you
|
|---|
| 63 | * get large spacings. Use txvStripLinefeeds to strip the
|
|---|
| 64 | * \r characters before setting the text.
|
|---|
| 65 | *
|
|---|
| 66 | * In short, to give the control any text, do this:
|
|---|
| 67 | +
|
|---|
| 68 | + PSZ psz = ... // whatever, load string
|
|---|
| 69 | + txvStripLinefeeds(&psz); // reallocates
|
|---|
| 70 | + WinSetWindowText(hwndTextView, psz);
|
|---|
| 71 | *
|
|---|
| 72 | * -- The control uses the \xFF (255) character internally as
|
|---|
| 73 | * an escape code for formatting commands. See "Escape codes"
|
|---|
| 74 | * below. If your text contains this character, you should
|
|---|
| 75 | * overwrite all occurences with spaces, or they will be
|
|---|
| 76 | * considered an escape code, which will cause problems.
|
|---|
| 77 | *
|
|---|
| 78 | * -- If you don't care about learning all the escape codes,
|
|---|
| 79 | * you can automatically have HTML code converted to the
|
|---|
| 80 | * XTextView format using txvConvertFromHTML, which will
|
|---|
| 81 | * automatically insert all the codes right from plain
|
|---|
| 82 | * HTML. In the above code, use txvConvertFromHTML instead
|
|---|
| 83 | * of txvStripLinefeeds.
|
|---|
| 84 | *
|
|---|
| 85 | * <B>Code page support</B>
|
|---|
| 86 | *
|
|---|
| 87 | * The XTextView control assumes that the text given to it uses
|
|---|
| 88 | * the same codepage as the message queue (thread) on which
|
|---|
| 89 | * the control is running. So if you need codepage support,
|
|---|
| 90 | * issue WinSetCp before creating the text view control.
|
|---|
| 91 | *
|
|---|
| 92 | * <B>Text formatting</B>
|
|---|
| 93 | *
|
|---|
| 94 | * The XTextView control has a default paragraph format which
|
|---|
| 95 | * determines how text is formatted. If you don't change this
|
|---|
| 96 | * format, the control performs no word-wrapping and displays
|
|---|
| 97 | * all text "as is", that is, practically no formatting is
|
|---|
| 98 | * performed.
|
|---|
| 99 | *
|
|---|
| 100 | * You can change the default paragraph format by sending
|
|---|
| 101 | * TXM_SETPARFORMAT to the control. This takes a XFMTPARAGRAPH
|
|---|
| 102 | * structure for input.
|
|---|
| 103 | *
|
|---|
| 104 | * To quickly enable word-wrapping only, we have the extra
|
|---|
| 105 | * TXM_SETWORDWRAP message. This changes the word-wrapping flag
|
|---|
| 106 | * in the default paragraph format only so you don't have to
|
|---|
| 107 | * mess with all the rest.
|
|---|
| 108 | *
|
|---|
| 109 | * The XTextView control is extremely fast in formatting. It
|
|---|
| 110 | * does pre-calculations once so that resizing the text
|
|---|
| 111 | * window does not perform a full reformat, but a quick
|
|---|
| 112 | * format based on the pre-calculations.
|
|---|
| 113 | *
|
|---|
| 114 | * Presently, formatting is done synchronously. It is planned
|
|---|
| 115 | * to put formatting into a separate thread. Performance is
|
|---|
| 116 | * acceptable already now unless very large texts (> 200 KB)
|
|---|
| 117 | * are formatted (tested on a PII-400 machine).
|
|---|
| 118 | *
|
|---|
| 119 | * <B>Presentation Parameters</B>
|
|---|
| 120 | *
|
|---|
| 121 | * The XTextView control recognizes the following presentation
|
|---|
| 122 | * parameters:
|
|---|
| 123 | *
|
|---|
| 124 | * -- PP_BACKGROUNDCOLOR; if not set, SYSCLR_DIALOGBACKGROUND
|
|---|
| 125 | * (per default gray) is used.
|
|---|
| 126 | *
|
|---|
| 127 | * -- PP_FOREGROUNDCOLOR: if not set, SYSCLR_WINDOWSTATICTEXT
|
|---|
| 128 | * (per default blue) is used to signify that the text
|
|---|
| 129 | * cannot be worked on.
|
|---|
| 130 | *
|
|---|
| 131 | * -- PP_FONTNAMESIZE: default font. This is the system font,
|
|---|
| 132 | * if not set.
|
|---|
| 133 | *
|
|---|
| 134 | * This implies that fonts and colors can be dropped on the
|
|---|
| 135 | * control in the normal way. Font changes will cause a reformat.
|
|---|
| 136 | *
|
|---|
| 137 | * Changing those presentation parameters is equivalent to
|
|---|
| 138 | * changing the corresponding fields in the default paragraph
|
|---|
| 139 | * format using TXM_SETPARFORMAT.
|
|---|
| 140 | *
|
|---|
| 141 | * <B>Escape codes</B>
|
|---|
| 142 | *
|
|---|
| 143 | * All XTextView escape codes start with a \xFF (255) character,
|
|---|
| 144 | * followed by at least one more character. The escape sequences
|
|---|
| 145 | * are variable in length and can have parameters. For details,
|
|---|
| 146 | * see textview.h where all these are listed.
|
|---|
| 147 | *
|
|---|
| 148 | * Escape codes are evaluated by txvFormatText during formatting.
|
|---|
| 149 | *
|
|---|
| 150 | * If you choose to give the text view control a text which
|
|---|
| 151 | * contains escape codes, you better make sure that you get the
|
|---|
| 152 | * exact codes right, or the text view control can crash. The
|
|---|
| 153 | * control has been optimized for speed, so no checking is done
|
|---|
| 154 | * on escape sequences.
|
|---|
| 155 | *
|
|---|
| 156 | * <B>Device-independent text formatting</B>
|
|---|
| 157 | *
|
|---|
| 158 | * If the features of the XTextView control satisfy your needs,
|
|---|
| 159 | * there's not much to worry about. However, if you're interested
|
|---|
| 160 | * in formatting the text yourself, here's more:
|
|---|
| 161 | *
|
|---|
| 162 | * This file has the txvFormatText function, which is capable
|
|---|
| 163 | * of formatting an input string into any HPS. This works for
|
|---|
| 164 | * windows (used by the text view control) and printers (used
|
|---|
| 165 | * by txvPrint). Word-wrapping is supported. This is used by
|
|---|
| 166 | * the XTextView control internally whenever (re)formatting is
|
|---|
| 167 | * needed: either when the text is set or the formatting parameters
|
|---|
| 168 | * (fonts, margins, etc.) have changed.
|
|---|
| 169 | *
|
|---|
| 170 | * These functions are designed to be used in a two-step process:
|
|---|
| 171 | * first format the text (using txvFormatText), then paint it
|
|---|
| 172 | * (using txvPaintText) for viewing or printing.
|
|---|
| 173 | * This speeds up painting dramatically, because formatting
|
|---|
| 174 | * might take some time.
|
|---|
| 175 | *
|
|---|
| 176 | * Note: Version numbering in this file relates to XWorkplace version
|
|---|
| 177 | * numbering.
|
|---|
| 178 | *
|
|---|
| 179 | *@@header "helpers\textview.h"
|
|---|
| 180 | *
|
|---|
| 181 | *@@added V0.9.1 (2000-02-13) [umoeller]
|
|---|
| 182 | */
|
|---|
| 183 |
|
|---|
| 184 | /*
|
|---|
| 185 | * Copyright (C) 2000 Ulrich Mller.
|
|---|
| 186 | * This program is part of the XWorkplace package.
|
|---|
| 187 | * This program is free software; you can redistribute it and/or modify
|
|---|
| 188 | * it under the terms of the GNU General Public License as published by
|
|---|
| 189 | * the Free Software Foundation, in version 2 as it comes in the COPYING
|
|---|
| 190 | * file of the XWorkplace main distribution.
|
|---|
| 191 | * This program is distributed in the hope that it will be useful,
|
|---|
| 192 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 193 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 194 | * GNU General Public License for more details.
|
|---|
| 195 | */
|
|---|
| 196 |
|
|---|
| 197 | #define OS2EMX_PLAIN_CHAR
|
|---|
| 198 | // this is needed for "os2emx.h"; if this is defined,
|
|---|
| 199 | // emx will define PSZ as _signed_ char, otherwise
|
|---|
| 200 | // as unsigned char
|
|---|
| 201 |
|
|---|
| 202 | #define OS2EMX_PLAIN_CHAR
|
|---|
| 203 | // this is needed for "os2emx.h"; if this is defined,
|
|---|
| 204 | // emx will define PSZ as _signed_ char, otherwise
|
|---|
| 205 | // as unsigned char
|
|---|
| 206 |
|
|---|
| 207 | #define INCL_WINWINDOWMGR
|
|---|
| 208 | #define INCL_WINFRAMEMGR
|
|---|
| 209 | #define INCL_WINMESSAGEMGR
|
|---|
| 210 | #define INCL_WININPUT
|
|---|
| 211 | #define INCL_WINRECTANGLES
|
|---|
| 212 | #define INCL_WINPOINTERS
|
|---|
| 213 | #define INCL_WINSYS
|
|---|
| 214 | #define INCL_WINSCROLLBARS
|
|---|
| 215 | #define INCL_WINSTDFONT
|
|---|
| 216 | #define INCL_WINCOUNTRY
|
|---|
| 217 |
|
|---|
| 218 | #define INCL_DEV
|
|---|
| 219 | #define INCL_SPL
|
|---|
| 220 | #define INCL_SPLDOSPRINT
|
|---|
| 221 |
|
|---|
| 222 | #define INCL_GPIPRIMITIVES
|
|---|
| 223 | #define INCL_GPILCIDS
|
|---|
| 224 | #define INCL_GPILOGCOLORTABLE
|
|---|
| 225 | #define INCL_GPITRANSFORMS
|
|---|
| 226 | #define INCL_GPIREGIONS
|
|---|
| 227 |
|
|---|
| 228 | #define INCL_ERRORS
|
|---|
| 229 | #include <os2.h>
|
|---|
| 230 |
|
|---|
| 231 | #include <stdlib.h>
|
|---|
| 232 | #include <stdio.h>
|
|---|
| 233 | #include <string.h>
|
|---|
| 234 |
|
|---|
| 235 | #include "setup.h" // code generation and debugging options
|
|---|
| 236 |
|
|---|
| 237 | #include "helpers\comctl.h"
|
|---|
| 238 | #include "helpers\gpih.h"
|
|---|
| 239 | #include "helpers\linklist.h"
|
|---|
| 240 | #include "helpers\stringh.h"
|
|---|
| 241 | #include "helpers\winh.h"
|
|---|
| 242 | #include "helpers\xstring.h" // extended string helpers
|
|---|
| 243 |
|
|---|
| 244 | #include "helpers\textview.h"
|
|---|
| 245 | #include "helpers\textv_html.h"
|
|---|
| 246 |
|
|---|
| 247 | #pragma hdrstop
|
|---|
| 248 |
|
|---|
| 249 | /*
|
|---|
| 250 | *@@category: Helpers\PM helpers\Window classes\XTextView control
|
|---|
| 251 | * See textview.c.
|
|---|
| 252 | */
|
|---|
| 253 |
|
|---|
| 254 | /* ******************************************************************
|
|---|
| 255 | *
|
|---|
| 256 | * Device-independent functions
|
|---|
| 257 | *
|
|---|
| 258 | ********************************************************************/
|
|---|
| 259 |
|
|---|
| 260 | /*
|
|---|
| 261 | *@@ txvInitFormat:
|
|---|
| 262 | *
|
|---|
| 263 | */
|
|---|
| 264 |
|
|---|
| 265 | VOID txvInitFormat(PXFORMATDATA pxfd)
|
|---|
| 266 | {
|
|---|
| 267 | memset(pxfd, 0, sizeof(XFORMATDATA));
|
|---|
| 268 | lstInit(&pxfd->llRectangles,
|
|---|
| 269 | TRUE); // auto-free items
|
|---|
| 270 | lstInit(&pxfd->llWords,
|
|---|
| 271 | TRUE); // auto-free items
|
|---|
| 272 | xstrInit(&pxfd->strViewText, 0);
|
|---|
| 273 | }
|
|---|
| 274 |
|
|---|
| 275 | /*
|
|---|
| 276 | *@@ SetSubFont:
|
|---|
| 277 | *
|
|---|
| 278 | *@@added V0.9.3 (2000-05-06) [umoeller]
|
|---|
| 279 | */
|
|---|
| 280 |
|
|---|
| 281 | STATIC VOID SetSubFont(HPS hps,
|
|---|
| 282 | PXFMTFONT pFont,
|
|---|
| 283 | ULONG ulPointSize,
|
|---|
| 284 | PSZ pszFaceName,
|
|---|
| 285 | ULONG flFormat)
|
|---|
| 286 | {
|
|---|
| 287 | CHAR ac[256];
|
|---|
| 288 | ULONG ul;
|
|---|
| 289 | POINTL ptlStart = {0, 0},
|
|---|
| 290 | aptl[257];
|
|---|
| 291 |
|
|---|
| 292 | if (pFont->lcid)
|
|---|
| 293 | {
|
|---|
| 294 | // font already loaded:
|
|---|
| 295 | if (GpiQueryCharSet(hps) == pFont->lcid)
|
|---|
| 296 | // font currently selected:
|
|---|
| 297 | GpiSetCharSet(hps, LCID_DEFAULT);
|
|---|
| 298 | GpiDeleteSetId(hps, pFont->lcid);
|
|---|
| 299 |
|
|---|
| 300 | }
|
|---|
| 301 |
|
|---|
| 302 | if (pszFaceName)
|
|---|
| 303 | pFont->lcid = gpihFindFont(hps,
|
|---|
| 304 | ulPointSize,
|
|---|
| 305 | TRUE, // family, not face name
|
|---|
| 306 | pszFaceName,
|
|---|
| 307 | flFormat,
|
|---|
| 308 | &pFont->FontMetrics);
|
|---|
| 309 | else
|
|---|
| 310 | pFont->lcid = LCID_DEFAULT; // 0
|
|---|
| 311 |
|
|---|
| 312 | GpiSetCharSet(hps, pFont->lcid);
|
|---|
| 313 | if (pFont->FontMetrics.fsDefn & FM_DEFN_OUTLINE)
|
|---|
| 314 | // is outline font:
|
|---|
| 315 | gpihSetPointSize(hps, ulPointSize);
|
|---|
| 316 |
|
|---|
| 317 | for (ul = 0;
|
|---|
| 318 | ul < 256;
|
|---|
| 319 | ul++)
|
|---|
| 320 | ac[ul] = ul;
|
|---|
| 321 |
|
|---|
| 322 | GpiQueryCharStringPosAt(hps,
|
|---|
| 323 | &ptlStart,
|
|---|
| 324 | 0,
|
|---|
| 325 | 254, // starting at one
|
|---|
| 326 | ac + 1, // starting at one
|
|---|
| 327 | NULL,
|
|---|
| 328 | aptl);
|
|---|
| 329 | // now compute width of every char
|
|---|
| 330 | for (ul = 1;
|
|---|
| 331 | ul < 256;
|
|---|
| 332 | ul++)
|
|---|
| 333 | {
|
|---|
| 334 | pFont->alCX[ul] = aptl[ul+1].x - aptl[ul].x;
|
|---|
| 335 | }
|
|---|
| 336 | }
|
|---|
| 337 |
|
|---|
| 338 | /*
|
|---|
| 339 | *@@ SetFormatFont:
|
|---|
| 340 | * creates logical fonts from the specified
|
|---|
| 341 | * font information.
|
|---|
| 342 | *
|
|---|
| 343 | *@@added V0.9.3 (2000-05-06) [umoeller]
|
|---|
| 344 | */
|
|---|
| 345 |
|
|---|
| 346 | STATIC VOID SetFormatFont(HPS hps, // in: HPS to select default font into
|
|---|
| 347 | PXFMTCHARACTER pxfmtc, // in/out: format data
|
|---|
| 348 | ULONG ulPointSize, // in: font point size (e.g. 12) or 0
|
|---|
| 349 | PSZ pszFaceName) // in: font face name (e.g. "Courier") or NULL
|
|---|
| 350 | {
|
|---|
| 351 | pxfmtc->lPointSize = ulPointSize;
|
|---|
| 352 |
|
|---|
| 353 | // regular
|
|---|
| 354 | SetSubFont(hps,
|
|---|
| 355 | &pxfmtc->fntRegular,
|
|---|
| 356 | ulPointSize,
|
|---|
| 357 | pszFaceName,
|
|---|
| 358 | 0);
|
|---|
| 359 |
|
|---|
| 360 | // bold
|
|---|
| 361 | SetSubFont(hps,
|
|---|
| 362 | &pxfmtc->fntBold,
|
|---|
| 363 | ulPointSize,
|
|---|
| 364 | pszFaceName,
|
|---|
| 365 | FATTR_SEL_BOLD);
|
|---|
| 366 |
|
|---|
| 367 | // italics
|
|---|
| 368 | SetSubFont(hps,
|
|---|
| 369 | &pxfmtc->fntItalics,
|
|---|
| 370 | ulPointSize,
|
|---|
| 371 | pszFaceName,
|
|---|
| 372 | FATTR_SEL_ITALIC);
|
|---|
| 373 |
|
|---|
| 374 | // bold italics
|
|---|
| 375 | SetSubFont(hps,
|
|---|
| 376 | &pxfmtc->fntBoldItalics,
|
|---|
| 377 | ulPointSize,
|
|---|
| 378 | pszFaceName,
|
|---|
| 379 | FATTR_SEL_BOLD | FATTR_SEL_ITALIC);
|
|---|
| 380 | }
|
|---|
| 381 |
|
|---|
| 382 | /*
|
|---|
| 383 | *@@ AppendCharNoCheck:
|
|---|
| 384 | *
|
|---|
| 385 | *@@added V0.9.3 (2000-05-07) [umoeller]
|
|---|
| 386 | */
|
|---|
| 387 |
|
|---|
| 388 | STATIC VOID AppendCharNoCheck(char **ppszNew,
|
|---|
| 389 | PULONG pcbNew,
|
|---|
| 390 | char **ppTarget,
|
|---|
| 391 | char c)
|
|---|
| 392 | {
|
|---|
| 393 | ULONG cbSizeThis = *ppTarget - *ppszNew;
|
|---|
| 394 | if (cbSizeThis >= *pcbNew)
|
|---|
| 395 | {
|
|---|
| 396 | // more mem needed:
|
|---|
| 397 | *pcbNew += 10000;
|
|---|
| 398 | *ppszNew = (PSZ)realloc(*ppszNew, *pcbNew);
|
|---|
| 399 | // if first call, pszNew is NULL, and realloc
|
|---|
| 400 | // behaves just like malloc
|
|---|
| 401 | // adjust target, because ptr might have changed
|
|---|
| 402 | *ppTarget = *ppszNew + cbSizeThis;
|
|---|
| 403 | }
|
|---|
| 404 |
|
|---|
| 405 | **ppTarget = c;
|
|---|
| 406 | (*ppTarget)++;
|
|---|
| 407 | }
|
|---|
| 408 |
|
|---|
| 409 | /*
|
|---|
| 410 | *@@ txvStripLinefeeds:
|
|---|
| 411 | * this removes all linefeeds (\r) from
|
|---|
| 412 | * the specified string to prepare it
|
|---|
| 413 | * for display with the text view control.
|
|---|
| 414 | *
|
|---|
| 415 | * This also replaces tabs (\t) with ulTabSize spaces.
|
|---|
| 416 | *
|
|---|
| 417 | * The buffer gets reallocated by this function, so it
|
|---|
| 418 | * must be free()'able.
|
|---|
| 419 | *
|
|---|
| 420 | *@@added V0.9.3 (2000-05-07) [umoeller]
|
|---|
| 421 | *@@changed V0.9.20 (2002-08-10) [umoeller]: now stripping \xFF too
|
|---|
| 422 | */
|
|---|
| 423 |
|
|---|
| 424 | VOID txvStripLinefeeds(char **ppszText,
|
|---|
| 425 | ULONG ulTabSize)
|
|---|
| 426 | {
|
|---|
| 427 | PSZ pSource = *ppszText;
|
|---|
| 428 | ULONG cbNew = 1000;
|
|---|
| 429 | PSZ pszNew = (PSZ)malloc(cbNew);
|
|---|
| 430 | PSZ pTarget = pszNew;
|
|---|
| 431 | ULONG ul;
|
|---|
| 432 |
|
|---|
| 433 | while (*pSource)
|
|---|
| 434 | {
|
|---|
| 435 | switch (*pSource)
|
|---|
| 436 | {
|
|---|
| 437 | case '\r':
|
|---|
| 438 | pSource++;
|
|---|
| 439 | break;
|
|---|
| 440 |
|
|---|
| 441 | case '\t':
|
|---|
| 442 | for (ul = 0;
|
|---|
| 443 | ul < ulTabSize;
|
|---|
| 444 | ul++)
|
|---|
| 445 | AppendCharNoCheck(&pszNew,
|
|---|
| 446 | &cbNew,
|
|---|
| 447 | &pTarget,
|
|---|
| 448 | ' ');
|
|---|
| 449 |
|
|---|
| 450 | // skip the tab
|
|---|
| 451 | pSource++;
|
|---|
| 452 | break;
|
|---|
| 453 |
|
|---|
| 454 | case '\xFF': // V0.9.20 (2002-08-10) [umoeller]
|
|---|
| 455 | AppendCharNoCheck(&pszNew,
|
|---|
| 456 | &cbNew,
|
|---|
| 457 | &pTarget,
|
|---|
| 458 | ' ');
|
|---|
| 459 | pSource++;
|
|---|
| 460 | break;
|
|---|
| 461 |
|
|---|
| 462 | default:
|
|---|
| 463 | AppendCharNoCheck(&pszNew,
|
|---|
| 464 | &cbNew,
|
|---|
| 465 | &pTarget,
|
|---|
| 466 | *pSource++);
|
|---|
| 467 | }
|
|---|
| 468 | }
|
|---|
| 469 |
|
|---|
| 470 | AppendCharNoCheck(&pszNew,
|
|---|
| 471 | &cbNew,
|
|---|
| 472 | &pTarget,
|
|---|
| 473 | '\n');
|
|---|
| 474 | AppendCharNoCheck(&pszNew,
|
|---|
| 475 | &cbNew,
|
|---|
| 476 | &pTarget,
|
|---|
| 477 | 0);
|
|---|
| 478 |
|
|---|
| 479 | free(*ppszText);
|
|---|
| 480 | *ppszText = pszNew;
|
|---|
| 481 | }
|
|---|
| 482 |
|
|---|
| 483 | /* ******************************************************************
|
|---|
| 484 | *
|
|---|
| 485 | * Device-independent text formatting
|
|---|
| 486 | *
|
|---|
| 487 | ********************************************************************/
|
|---|
| 488 |
|
|---|
| 489 | /*
|
|---|
| 490 | *@@ strhFindEOL2:
|
|---|
| 491 | * finds the end of a line.
|
|---|
| 492 | *
|
|---|
| 493 | * An "end of line" means the next \r, \n, or \0 character
|
|---|
| 494 | * after *ppszSearchIn.
|
|---|
| 495 | *
|
|---|
| 496 | * This returns the pointer to that exact character, which
|
|---|
| 497 | * can be equal or higher than *ppszSearchIn.
|
|---|
| 498 | * This should never return NULL because at some point,
|
|---|
| 499 | * there will be a null byte in your string (unless you have
|
|---|
| 500 | * a heap problem).
|
|---|
| 501 | *
|
|---|
| 502 | * If the EOL character is not null (\0), *ppszSearchIN is
|
|---|
| 503 | * advanced to the first character of the _next_ line. This
|
|---|
| 504 | * can be the EOL pointer plus one if you have a UNIX-style
|
|---|
| 505 | * string (\n only at the end of each line) or EOL + 2 for
|
|---|
| 506 | * DOS and OS/2-style EOLs (which have \r\n at the end of
|
|---|
| 507 | * each line).
|
|---|
| 508 | *
|
|---|
| 509 | *@added V0.9.3 (2000-05-06) [umoeller]
|
|---|
| 510 | */
|
|---|
| 511 |
|
|---|
| 512 | STATIC PSZ strhFindEOL2(PSZ *ppszSearchIn, // in: where to search
|
|---|
| 513 | PULONG pulOffset) // out: offset (ptr can be NULL)
|
|---|
| 514 | {
|
|---|
| 515 | PSZ pThis = *ppszSearchIn,
|
|---|
| 516 | prc = NULL;
|
|---|
| 517 | while (TRUE)
|
|---|
| 518 | {
|
|---|
| 519 | if ( (*pThis == '\r') || (*pThis == '\n') || (*pThis == 0) )
|
|---|
| 520 | {
|
|---|
| 521 | prc = pThis;
|
|---|
| 522 | break;
|
|---|
| 523 | }
|
|---|
| 524 | pThis++;
|
|---|
| 525 | }
|
|---|
| 526 |
|
|---|
| 527 | // before modifying pointer, store offset
|
|---|
| 528 | if (pulOffset)
|
|---|
| 529 | *pulOffset = prc - *ppszSearchIn;
|
|---|
| 530 |
|
|---|
| 531 | if (*prc == 0)
|
|---|
| 532 | {
|
|---|
| 533 | // null byte (end of string):
|
|---|
| 534 | *ppszSearchIn = prc;
|
|---|
| 535 | }
|
|---|
| 536 | else
|
|---|
| 537 | {
|
|---|
| 538 | // not null byte (end of string):
|
|---|
| 539 | // skip following newline characters
|
|---|
| 540 | if (*prc == '\r')
|
|---|
| 541 | {
|
|---|
| 542 | if ( *(prc+1) == '\n')
|
|---|
| 543 | // we have a \r char next,
|
|---|
| 544 | // that's the DOS and OS/2 format (\r\n):
|
|---|
| 545 | // skip that too
|
|---|
| 546 | *ppszSearchIn = prc + 2;
|
|---|
| 547 | else
|
|---|
| 548 | *ppszSearchIn = prc + 1;
|
|---|
| 549 | }
|
|---|
| 550 | else if (*prc == '\n')
|
|---|
| 551 | // UNIX format (used by HTML formatter also):
|
|---|
| 552 | *ppszSearchIn = prc + 1;
|
|---|
| 553 | }
|
|---|
| 554 |
|
|---|
| 555 | // now:
|
|---|
| 556 | // 1) prc points to the \r, \n, or \0 character (EOL)
|
|---|
| 557 | // 2) *ppszSearchIn has been advanced to the first character
|
|---|
| 558 | // of the next line or points to the \0 character
|
|---|
| 559 |
|
|---|
| 560 | return prc;
|
|---|
| 561 | }
|
|---|
| 562 |
|
|---|
| 563 | /* #define TXVFRECTF_EMPTY 0x0001
|
|---|
| 564 | #define TXVFRECTF_PARAGRAPHDONE 0x0002
|
|---|
| 565 | #define TXVFRECTF_WORDSLEFT 0x0004
|
|---|
| 566 | #define TXVFRECTF_STOPPEDONESCAPE 0x0008
|
|---|
| 567 | #define TXVFRECTF_ENDOFTEXT 0x0010
|
|---|
| 568 | */
|
|---|
| 569 |
|
|---|
| 570 | /*
|
|---|
| 571 | *@@ FORMATLINEBUF:
|
|---|
| 572 | * worker structure to store various data
|
|---|
| 573 | * in txvFormatText in between CreateWord
|
|---|
| 574 | * calls. This has been created for speed
|
|---|
| 575 | * so we don't have to pass all these on
|
|---|
| 576 | * the stack all the time.
|
|---|
| 577 | *
|
|---|
| 578 | *@@added V0.9.3 (2000-05-06) [umoeller]
|
|---|
| 579 | */
|
|---|
| 580 |
|
|---|
| 581 | typedef struct _FORMATLINEBUF
|
|---|
| 582 | {
|
|---|
| 583 | PSZ pLastChar; // ptr to null terminator in text
|
|---|
| 584 |
|
|---|
| 585 | // formatting data; this is set by txvFormatText according
|
|---|
| 586 | // to escape characters and read by txvCreateRectangle
|
|---|
| 587 | XFMTPARAGRAPH fmtp;
|
|---|
| 588 | PXFMTCHARACTER pfmtc; // pointer to character formatting data
|
|---|
| 589 | PXFMTFONT pfmtf; // pointer to font to use
|
|---|
| 590 |
|
|---|
| 591 | BOOL fPre,
|
|---|
| 592 | fBold,
|
|---|
| 593 | fItalics;
|
|---|
| 594 |
|
|---|
| 595 | // current anchor
|
|---|
| 596 | PCSZ pcszCurrentLinkTarget;
|
|---|
| 597 | // this is != NULL if we're currently in a link block
|
|---|
| 598 | // and points to an item in XFORMATDATA.llLinks
|
|---|
| 599 | // (simply copied to the word structs that are created)
|
|---|
| 600 |
|
|---|
| 601 | // data copied to TXVWORD
|
|---|
| 602 | LONG lcid;
|
|---|
| 603 | LONG lPointSize;
|
|---|
| 604 | ULONG flChar; // any combination of CHS_UNDERSCORE and CHS_STRIKEOUT
|
|---|
| 605 |
|
|---|
| 606 | // counters, ...
|
|---|
| 607 | LONG lXCurrent; // current X position while adding words to rectangle
|
|---|
| 608 | } FORMATLINEBUF, *PFORMATLINEBUF;
|
|---|
| 609 |
|
|---|
| 610 | /*
|
|---|
| 611 | *@@ CreateWord:
|
|---|
| 612 | *
|
|---|
| 613 | * -- If the word ends with one or several spaces,
|
|---|
| 614 | * ppStartOfWord is set to the beginning of the
|
|---|
| 615 | * next word (non-space character).
|
|---|
| 616 | * pWord->ulFlags is set to 0.
|
|---|
| 617 | *
|
|---|
| 618 | * -- If the word ends with an escape character,
|
|---|
| 619 | * ppStartOfWord is set to point to the escape,
|
|---|
| 620 | * which must be handled by the caller.
|
|---|
| 621 | * pWord->ulFlags is set to TXVWORDF_GLUEWITHNEXT.
|
|---|
| 622 | *
|
|---|
| 623 | * -- If the word ends with a \n or \r,
|
|---|
| 624 | * ppStartOfWord is set to the beginning of the
|
|---|
| 625 | * next line (first char after \n or \r). This
|
|---|
| 626 | * may be another \n or \r, but the first one
|
|---|
| 627 | * is skipped.
|
|---|
| 628 | * pWord->ulFlags is set to TXVWORDF_LINEBREAK or
|
|---|
| 629 | * TXVWORDF_LINEFEED.
|
|---|
| 630 | *
|
|---|
| 631 | *@@added V0.9.3 (2000-05-14) [umoeller]
|
|---|
| 632 | *@@changed V0.9.20 (2002-08-10) [umoeller]: rewrote link implementation
|
|---|
| 633 | */
|
|---|
| 634 |
|
|---|
| 635 | STATIC PTXVWORD CreateWord(HPS hps,
|
|---|
| 636 | PSZ *ppStartOfWord,
|
|---|
| 637 | PFORMATLINEBUF pflbuf)
|
|---|
| 638 | {
|
|---|
| 639 | PTXVWORD pWord = NULL;
|
|---|
| 640 |
|
|---|
| 641 | // find next word:
|
|---|
| 642 | if (**ppStartOfWord)
|
|---|
| 643 | {
|
|---|
| 644 | PSZ pWordStart = *ppStartOfWord,
|
|---|
| 645 | pWordEnd = NULL;
|
|---|
| 646 | PSZ pCheck = *ppStartOfWord;
|
|---|
| 647 | ULONG cChars = 0;
|
|---|
| 648 | // cCheck = 0;
|
|---|
| 649 |
|
|---|
| 650 | pWord = (PTXVWORD)malloc(sizeof(TXVWORD));
|
|---|
| 651 | memset(pWord, 0, sizeof(TXVWORD));
|
|---|
| 652 | // this includes fIsEscapeSequence = FALSE;
|
|---|
| 653 | pWord->pStart = pWordStart;
|
|---|
| 654 |
|
|---|
| 655 | // initially, this has pWordStart pointing
|
|---|
| 656 | // to *ppStartOfWord. If a word is found,
|
|---|
| 657 | // pWordStart is set to the first char of
|
|---|
| 658 | // the word and pWordEnd receives the
|
|---|
| 659 | // pointer to the first character after the word (probably space)
|
|---|
| 660 | if (strhGetWord(&pWordStart, // in/out
|
|---|
| 661 | pflbuf->pLastChar,
|
|---|
| 662 | " ",
|
|---|
| 663 | "\x0d\x0a \xFF", // in: end chars; includes our escape!
|
|---|
| 664 | &pWordEnd)) // out: first char after word
|
|---|
| 665 | {
|
|---|
| 666 | // whoa, found a word:
|
|---|
| 667 | while (*pWordEnd == ' ')
|
|---|
| 668 | pWordEnd++;
|
|---|
| 669 |
|
|---|
| 670 | cChars = (pWordEnd - *ppStartOfWord);
|
|---|
| 671 | }
|
|---|
| 672 |
|
|---|
| 673 | if (cChars)
|
|---|
| 674 | {
|
|---|
| 675 | POINTL aptlText[TXTBOX_COUNT];
|
|---|
| 676 | // cChars is != 0 if strhGetWord succeeded AND the
|
|---|
| 677 | // line is not empty, so go on
|
|---|
| 678 | // cCheck = cChars;
|
|---|
| 679 |
|
|---|
| 680 | // advance input pointer
|
|---|
| 681 | *ppStartOfWord = pWordEnd;
|
|---|
| 682 |
|
|---|
| 683 | GpiQueryTextBox(hps,
|
|---|
| 684 | // no. of chars since start of word:
|
|---|
| 685 | cChars,
|
|---|
| 686 | // first char:
|
|---|
| 687 | pCheck,
|
|---|
| 688 | TXTBOX_COUNT,
|
|---|
| 689 | (PPOINTL)&aptlText);
|
|---|
| 690 |
|
|---|
| 691 | pWord->cChars = cChars;
|
|---|
| 692 | pWord->ulFlags = 0;
|
|---|
| 693 |
|
|---|
| 694 | if (cChars)
|
|---|
| 695 | pWord->ulCXWithSpaces = aptlText[TXTBOX_TOPRIGHT].x;
|
|---|
| 696 | else
|
|---|
| 697 | pWord->ulCXWithSpaces = 0;
|
|---|
| 698 |
|
|---|
| 699 | pWord->ulCY = aptlText[TXTBOX_TOPRIGHT].y
|
|---|
| 700 | - aptlText[TXTBOX_BOTTOMRIGHT].y;
|
|---|
| 701 | // store base line ofs; aptlText[TXTBOX_BOTTOMRIGHT].y is negative
|
|---|
| 702 | // if the string has any characters drawn below the base line, e.g.
|
|---|
| 703 | // for the "g" and "y" characters
|
|---|
| 704 | pWord->ulBaseLineOfs = -aptlText[TXTBOX_BOTTOMRIGHT].y;
|
|---|
| 705 | }
|
|---|
| 706 | else
|
|---|
| 707 | {
|
|---|
| 708 | // no word found or empty line:
|
|---|
| 709 | pWord->ulCY = pflbuf->pfmtf->FontMetrics.lMaxBaselineExt;
|
|---|
| 710 | }
|
|---|
| 711 |
|
|---|
| 712 | switch (**ppStartOfWord)
|
|---|
| 713 | {
|
|---|
| 714 | case TXVESC_CHAR: // '\xFF':
|
|---|
| 715 | pWord->ulFlags = TXVWORDF_GLUEWITHNEXT;
|
|---|
| 716 | break;
|
|---|
| 717 |
|
|---|
| 718 | case '\n':
|
|---|
| 719 | pWord->ulFlags = TXVWORDF_LINEBREAK;
|
|---|
| 720 | (*ppStartOfWord)++; // skip \n
|
|---|
| 721 | break;
|
|---|
| 722 |
|
|---|
| 723 | case '\r':
|
|---|
| 724 | pWord->ulFlags = TXVWORDF_LINEFEED;
|
|---|
| 725 | (*ppStartOfWord)++; // skip \r
|
|---|
| 726 | break;
|
|---|
| 727 | }
|
|---|
| 728 |
|
|---|
| 729 | pWord->lcid = pflbuf->pfmtf->lcid;
|
|---|
| 730 | pWord->lPointSize = pflbuf->lPointSize;
|
|---|
| 731 | pWord->flChar = pflbuf->flChar;
|
|---|
| 732 |
|
|---|
| 733 | pWord->pcszLinkTarget = pflbuf->pcszCurrentLinkTarget; // 0 if none
|
|---|
| 734 | }
|
|---|
| 735 |
|
|---|
| 736 | return pWord;
|
|---|
| 737 | }
|
|---|
| 738 |
|
|---|
| 739 | /*
|
|---|
| 740 | *@@ ProcessEscapes:
|
|---|
| 741 | * gets called when txvFormatText stops on an
|
|---|
| 742 | * escape character (\xFF). This evaluates the
|
|---|
| 743 | * escape sequence, reacts accordingly, and
|
|---|
| 744 | * advances *ppCurrent to after the escape
|
|---|
| 745 | * sequence so that regular processing can
|
|---|
| 746 | * continue.
|
|---|
| 747 | *
|
|---|
| 748 | * There are two types of escape sequences:
|
|---|
| 749 | *
|
|---|
| 750 | * -- Those which are only relevant during word processing,
|
|---|
| 751 | * such as character formatting attributes (bold, italics,
|
|---|
| 752 | * font, size, ...). Those affect the TXVWORD structure
|
|---|
| 753 | * directly and are thus never evaluated in step 2,
|
|---|
| 754 | * rectangles correlation.
|
|---|
| 755 | *
|
|---|
| 756 | * -- Those which affect spacings, margins, etc. (paragraph
|
|---|
| 757 | * formatting). These need to be re-evaluated even during
|
|---|
| 758 | * "quick" format, without words being recalculated, because
|
|---|
| 759 | * those spacings affect the output rectangles.
|
|---|
| 760 | *
|
|---|
| 761 | * If one of those sequences is encountered, this function
|
|---|
| 762 | * appends a special TXVWORD structure to XFORMATDATA.llWords.
|
|---|
| 763 | *
|
|---|
| 764 | *@@added V0.9.3 (2000-05-07) [umoeller]
|
|---|
| 765 | */
|
|---|
| 766 |
|
|---|
| 767 | STATIC PTXVWORD ProcessEscapes(char **ppCurrent, // in/out: current position; initially points to esc char
|
|---|
| 768 | PXFORMATDATA pxfd, // in/out: formatting data
|
|---|
| 769 | PFORMATLINEBUF pflbuf, // in/out: formatting buffer
|
|---|
| 770 | BOOL fWordsProcessed) // FALSE during step 1 (words processing),
|
|---|
| 771 | // TRUE during step 2 (rectangles correlation)
|
|---|
| 772 | {
|
|---|
| 773 | PTXVWORD pEscapeWord = NULL;
|
|---|
| 774 |
|
|---|
| 775 | // this is set to TRUE either above or by txvCreateRectangle if
|
|---|
| 776 | // an escape character was found; txvCreateRectangle
|
|---|
| 777 | // then sets pCurrent to the escape character (\xFF)
|
|---|
| 778 | CHAR cCode1 = *((*ppCurrent) + 1);
|
|---|
| 779 | CHAR cCode2 = *((*ppCurrent) + 2);
|
|---|
| 780 | ULONG ulSkip = 3; // per default, skip \xFF plus two
|
|---|
| 781 | CHAR szDecimal[10];
|
|---|
| 782 | LONG lDecimal;
|
|---|
| 783 |
|
|---|
| 784 | BOOL fCreateWord = FALSE,
|
|---|
| 785 | fPaintEscapeWord = FALSE;
|
|---|
| 786 |
|
|---|
| 787 | switch (cCode1)
|
|---|
| 788 | {
|
|---|
| 789 | case 1: // change font:
|
|---|
| 790 | // three decimals follow specifying the font
|
|---|
| 791 | memcpy(szDecimal, (*ppCurrent) + 2, 3);
|
|---|
| 792 | szDecimal[3] = 0;
|
|---|
| 793 | lDecimal = atoi(szDecimal);
|
|---|
| 794 | if (lDecimal == 0)
|
|---|
| 795 | pflbuf->pfmtc = &pxfd->fmtcStandard;
|
|---|
| 796 | else if (lDecimal == 1)
|
|---|
| 797 | pflbuf->pfmtc = &pxfd->fmtcCode;
|
|---|
| 798 | ulSkip = 5;
|
|---|
| 799 | break;
|
|---|
| 800 |
|
|---|
| 801 | case 2: // B or /B
|
|---|
| 802 | if (cCode2 == 1)
|
|---|
| 803 | pflbuf->fBold = TRUE;
|
|---|
| 804 | else
|
|---|
| 805 | pflbuf->fBold = FALSE;
|
|---|
| 806 | break;
|
|---|
| 807 |
|
|---|
| 808 | case 3: // I or /I
|
|---|
| 809 | if (cCode2 == 1)
|
|---|
| 810 | pflbuf->fItalics = TRUE;
|
|---|
| 811 | else
|
|---|
| 812 | pflbuf->fItalics = FALSE;
|
|---|
| 813 | break;
|
|---|
| 814 |
|
|---|
| 815 | case 4: // U or /U
|
|---|
| 816 | if (cCode2 == 1)
|
|---|
| 817 | pflbuf->flChar |= CHS_UNDERSCORE;
|
|---|
| 818 | else
|
|---|
| 819 | pflbuf->flChar &= ~CHS_UNDERSCORE;
|
|---|
| 820 | break;
|
|---|
| 821 |
|
|---|
| 822 | case 5: // STRIKE or /STRIKE
|
|---|
| 823 | if (cCode2 == 1)
|
|---|
| 824 | pflbuf->flChar |= CHS_STRIKEOUT;
|
|---|
| 825 | else
|
|---|
| 826 | pflbuf->flChar &= ~CHS_STRIKEOUT;
|
|---|
| 827 | break;
|
|---|
| 828 |
|
|---|
| 829 | case 6: // A HREF= (link)
|
|---|
| 830 | // changed implementation V0.9.20 (2002-08-10) [umoeller]
|
|---|
| 831 | {
|
|---|
| 832 | // this is variable in length and terminated with
|
|---|
| 833 | // another 0xFF char; what's in between is the
|
|---|
| 834 | // link target name and gets appended to
|
|---|
| 835 | // XFORMATDATA.llLinks
|
|---|
| 836 | PSZ pEnd;
|
|---|
| 837 | if (pEnd = strchr((*ppCurrent) + 2, 0xFF))
|
|---|
| 838 | {
|
|---|
| 839 | PSZ pszNewLink = strhSubstr((*ppCurrent) + 2, pEnd);
|
|---|
| 840 | lstAppendItem(&pxfd->llLinks,
|
|---|
| 841 | pszNewLink);
|
|---|
| 842 |
|
|---|
| 843 | pflbuf->pcszCurrentLinkTarget = pszNewLink;
|
|---|
| 844 |
|
|---|
| 845 | ulSkip = pEnd - *ppCurrent + 1;
|
|---|
| 846 | }
|
|---|
| 847 | }
|
|---|
| 848 | break;
|
|---|
| 849 |
|
|---|
| 850 | case 7: // /A HREF (end of link)
|
|---|
| 851 | pflbuf->pcszCurrentLinkTarget = NULL;
|
|---|
| 852 | ulSkip = 2;
|
|---|
| 853 | break;
|
|---|
| 854 |
|
|---|
| 855 | case 8: // A NAME= (anchor name)
|
|---|
| 856 | {
|
|---|
| 857 | // this is variable in length and terminated with
|
|---|
| 858 | // another 0xFF char; we completely ignore this
|
|---|
| 859 | // here and just skip the anchor name, this is
|
|---|
| 860 | // only used with TXM_JUMPTOANCHORNAME, which then
|
|---|
| 861 | // searches the buffer
|
|---|
| 862 | PSZ pEnd;
|
|---|
| 863 | if (pEnd = strchr((*ppCurrent) + 2, 0xFF))
|
|---|
| 864 | {
|
|---|
| 865 | ulSkip = pEnd - *ppCurrent + 1;
|
|---|
| 866 | // store this with the other words so we can
|
|---|
| 867 | // find this word later
|
|---|
| 868 | fCreateWord = TRUE;
|
|---|
| 869 | // and store this with the rectangles
|
|---|
| 870 | fPaintEscapeWord = TRUE;
|
|---|
| 871 | }
|
|---|
| 872 | }
|
|---|
| 873 | break;
|
|---|
| 874 |
|
|---|
| 875 | case 0x10: // relative point size in percent
|
|---|
| 876 | // three characters follow specifying the
|
|---|
| 877 | // percentage
|
|---|
| 878 | memcpy(szDecimal, (*ppCurrent) + 2, 3);
|
|---|
| 879 | szDecimal[3] = 0;
|
|---|
| 880 | lDecimal = atoi(szDecimal);
|
|---|
| 881 |
|
|---|
| 882 | pflbuf->lPointSize = pflbuf->pfmtc->lPointSize * lDecimal / 100;
|
|---|
| 883 | ulSkip = 5;
|
|---|
| 884 | break;
|
|---|
| 885 |
|
|---|
| 886 | case 0x20: // left margin changed:
|
|---|
| 887 | memcpy(szDecimal, (*ppCurrent) + 2, 4); // four decimals xxxx
|
|---|
| 888 | szDecimal[4] = 0;
|
|---|
| 889 | lDecimal = atoi(szDecimal);
|
|---|
| 890 |
|
|---|
| 891 | // this is based on the current average font width, so
|
|---|
| 892 | // find this:
|
|---|
| 893 | pflbuf->fmtp.lLeftMargin = (lDecimal
|
|---|
| 894 | * pflbuf->lPointSize);
|
|---|
| 895 | ulSkip = 6;
|
|---|
| 896 | fCreateWord = TRUE; // for rectangle correlation
|
|---|
| 897 | break;
|
|---|
| 898 |
|
|---|
| 899 | case 0x21: // first line margin changed:
|
|---|
| 900 | memcpy(szDecimal, (*ppCurrent) + 2, 4); // +xxx, -xxx
|
|---|
| 901 | szDecimal[4] = 0;
|
|---|
| 902 | lDecimal = atoi(szDecimal);
|
|---|
| 903 |
|
|---|
| 904 | // this is based on the current average font width, so
|
|---|
| 905 | // find this:
|
|---|
| 906 | pflbuf->fmtp.lFirstLineMargin = (lDecimal
|
|---|
| 907 | * pflbuf->lPointSize);
|
|---|
| 908 | ulSkip = 6;
|
|---|
| 909 | fCreateWord = TRUE; // for rectangle correlation
|
|---|
| 910 | break;
|
|---|
| 911 |
|
|---|
| 912 | case 0x22: // tab: forward current X to left margin
|
|---|
| 913 | pflbuf->lXCurrent = pflbuf->fmtp.lLeftMargin;
|
|---|
| 914 |
|
|---|
| 915 | ulSkip = 2;
|
|---|
| 916 | fCreateWord = TRUE; // for rectangle correlation
|
|---|
| 917 | break;
|
|---|
| 918 |
|
|---|
| 919 | case 0x23: // marker: store this in output, this needs
|
|---|
| 920 | // to be painted
|
|---|
| 921 | fCreateWord = TRUE;
|
|---|
| 922 | fPaintEscapeWord = TRUE;
|
|---|
| 923 | ulSkip = 3;
|
|---|
| 924 | break;
|
|---|
| 925 |
|
|---|
| 926 | case 0x30: // spacing before paragraph:
|
|---|
| 927 | // four chars follow with either "####" or decimal spacing
|
|---|
| 928 | memcpy(szDecimal, (*ppCurrent) + 2, 4);
|
|---|
| 929 | szDecimal[4] = 0;
|
|---|
| 930 | if (memcmp(szDecimal, "####", 4) == 0)
|
|---|
| 931 | // reset to default:
|
|---|
| 932 | pflbuf->fmtp.lSpaceBefore = pxfd->fmtpStandard.lSpaceBefore;
|
|---|
| 933 | else
|
|---|
| 934 | {
|
|---|
| 935 | lDecimal = atoi(szDecimal);
|
|---|
| 936 | pflbuf->fmtp.lSpaceBefore = lDecimal;
|
|---|
| 937 | }
|
|---|
| 938 | ulSkip = 6;
|
|---|
| 939 | fCreateWord = TRUE; // for rectangle correlation
|
|---|
| 940 | break;
|
|---|
| 941 |
|
|---|
| 942 | case 0x31: // spacing before paragraph:
|
|---|
| 943 | // four chars follow with either "####" or decimal spacing
|
|---|
| 944 | memcpy(szDecimal, (*ppCurrent) + 2, 4);
|
|---|
| 945 | szDecimal[4] = 0;
|
|---|
| 946 | if (memcmp(szDecimal, "####", 4) == 0)
|
|---|
| 947 | // reset to default:
|
|---|
| 948 | pflbuf->fmtp.lSpaceAfter = pxfd->fmtpStandard.lSpaceAfter;
|
|---|
| 949 | else
|
|---|
| 950 | {
|
|---|
| 951 | lDecimal = atoi(szDecimal);
|
|---|
| 952 | pflbuf->fmtp.lSpaceAfter = lDecimal;
|
|---|
| 953 | }
|
|---|
| 954 | ulSkip = 6;
|
|---|
| 955 | fCreateWord = TRUE; // for rectangle correlation
|
|---|
| 956 | break;
|
|---|
| 957 |
|
|---|
| 958 | case 0x32: // word-wrapping:
|
|---|
| 959 | // here follows a single char being "0" or "1"
|
|---|
| 960 | if ( *((*ppCurrent) + 2) == '0')
|
|---|
| 961 | pflbuf->fmtp.fWordWrap = FALSE;
|
|---|
| 962 | else
|
|---|
| 963 | pflbuf->fmtp.fWordWrap = TRUE;
|
|---|
| 964 | fCreateWord = TRUE; // for rectangle correlation
|
|---|
| 965 | }
|
|---|
| 966 |
|
|---|
| 967 | if (fCreateWord) // append for rectangle correlation?
|
|---|
| 968 | if (!fWordsProcessed) // are we processing words still (step 1)?
|
|---|
| 969 | {
|
|---|
| 970 | // yes: append to list for rectangle correlation later
|
|---|
| 971 | pEscapeWord = (PTXVWORD)malloc(sizeof(TXVWORD));
|
|---|
| 972 | memset(pEscapeWord, 0, sizeof(TXVWORD));
|
|---|
| 973 | // mark as escape sequence
|
|---|
| 974 | pEscapeWord->pStart = *ppCurrent;
|
|---|
| 975 | pEscapeWord->cChars = ulSkip;
|
|---|
| 976 | pEscapeWord->cEscapeCode = *(*ppCurrent + 1);
|
|---|
| 977 | pEscapeWord->fPaintEscapeWord = fPaintEscapeWord;
|
|---|
| 978 | pEscapeWord->pcszLinkTarget = pflbuf->pcszCurrentLinkTarget;
|
|---|
| 979 | // V0.9.20 (2002-08-10) [umoeller]
|
|---|
| 980 | // NULL if none
|
|---|
| 981 | if (fPaintEscapeWord)
|
|---|
| 982 | {
|
|---|
| 983 | pEscapeWord->lX = pflbuf->lXCurrent;
|
|---|
| 984 | pEscapeWord->lcid = pflbuf->pfmtf->lcid;
|
|---|
| 985 | pEscapeWord->lPointSize = pflbuf->lPointSize;
|
|---|
| 986 | pEscapeWord->flChar = pflbuf->flChar;
|
|---|
| 987 | }
|
|---|
| 988 | lstAppendItem(&pxfd->llWords, pEscapeWord);
|
|---|
| 989 | }
|
|---|
| 990 |
|
|---|
| 991 | if (!fWordsProcessed)
|
|---|
| 992 | // if we're still processing words, advance
|
|---|
| 993 | // current pointer by the escape length
|
|---|
| 994 | *ppCurrent += ulSkip;
|
|---|
| 995 |
|
|---|
| 996 | return pEscapeWord;
|
|---|
| 997 | }
|
|---|
| 998 |
|
|---|
| 999 | /*
|
|---|
| 1000 | *@@ txvFormatText:
|
|---|
| 1001 | * this is the core function to text formatting, which
|
|---|
| 1002 | * must be done before the text can be painted into an
|
|---|
| 1003 | * HPS. See the top of textview.c for details.
|
|---|
| 1004 | *
|
|---|
| 1005 | * Even though this function does not seem to have a
|
|---|
| 1006 | * lot of parameters, it is extremely powerful. This
|
|---|
| 1007 | * function handles paragraph and character formatting
|
|---|
| 1008 | * automatically. See XFMTPARAGRAPH and XFMTCHARACTER
|
|---|
| 1009 | * for possible formatting attributes, which are part
|
|---|
| 1010 | * of the XFORMATDATA structure passed to this function.
|
|---|
| 1011 | *
|
|---|
| 1012 | * "Formatting" means splitting up any zero-terminated
|
|---|
| 1013 | * string (XFORMATDATA.pszViewText) into a possibly
|
|---|
| 1014 | * large list of TXVRECTANGLE structures, which each
|
|---|
| 1015 | * hold a rectangle to be painted. This allows for
|
|---|
| 1016 | * extremely fast painting.
|
|---|
| 1017 | *
|
|---|
| 1018 | * Each TXVRECTANGLE in turn holds several "words" to
|
|---|
| 1019 | * be painted. A word consists of a TXVWORD structure
|
|---|
| 1020 | * and is normally a sequence of characters between
|
|---|
| 1021 | * spaces, \n and \r characters. As an exception, if
|
|---|
| 1022 | * escape sequences come up, such a "word" is split up
|
|---|
| 1023 | * into several words because character formatting
|
|---|
| 1024 | * (font, size, ...) is done on a per-word basis when painting.
|
|---|
| 1025 | *
|
|---|
| 1026 | * This approach allows for quicker word-wrapping when only
|
|---|
| 1027 | * the output (paint) rectangle is changed because we don't
|
|---|
| 1028 | * have to re-calculate all the character widths (TXVWORD) once we
|
|---|
| 1029 | * got the words. Instead, when re-formatting, we just recompose
|
|---|
| 1030 | * the rectangles based on the words we calculated already.
|
|---|
| 1031 | * Of course, when character widths change (e.g. because
|
|---|
| 1032 | * fonts are changed), everything has to be redone.
|
|---|
| 1033 | *
|
|---|
| 1034 | * Processing depends on the current formatting settings
|
|---|
| 1035 | * of the XFORMATDATA structure passed to this func and
|
|---|
| 1036 | * can become quite complicated:
|
|---|
| 1037 | *
|
|---|
| 1038 | * -- In the simplest possible formatting mode, that is, if
|
|---|
| 1039 | * word wrapping is disabled, each such TXVRECTANGLE
|
|---|
| 1040 | * structure will hold one paragraph from the text
|
|---|
| 1041 | * (that is, the text between two \n chars).
|
|---|
| 1042 | *
|
|---|
| 1043 | * -- If word wrapping is enabled, each paragraph in the text
|
|---|
| 1044 | * can consist of several such rectangles if the paragraph
|
|---|
| 1045 | * does not fit into one line. In that case, we create
|
|---|
| 1046 | * one XFMTRECTANGLE for each line which is needed to
|
|---|
| 1047 | * display the paragraph word-wrapped.
|
|---|
| 1048 | *
|
|---|
| 1049 | * This uses an XFORMATDATA structure for input and output
|
|---|
| 1050 | * (besides the other parameters).
|
|---|
| 1051 | *
|
|---|
| 1052 | * On input, specify the following:
|
|---|
| 1053 | *
|
|---|
| 1054 | * -- hps: window or printer HPS. This is used for
|
|---|
| 1055 | * formatting only, but nothing is painted.
|
|---|
| 1056 | *
|
|---|
| 1057 | * -- XFORMATDATA.pszViewText: the text to be formatted.
|
|---|
| 1058 | * This must follow certain conventions; the \xFF,
|
|---|
| 1059 | * \r, and \n characters have a special meaning.
|
|---|
| 1060 | * See the top of textview.c for details.
|
|---|
| 1061 | *
|
|---|
| 1062 | * -- XFORMATDATA.fmtpStandard, fmtcStandard, fmtcCode:
|
|---|
| 1063 | * paragraph and character formatting attributes.
|
|---|
| 1064 | * For the simplest possible formatting, memset
|
|---|
| 1065 | * all these to 0. Word-wrapping depends on
|
|---|
| 1066 | * the paragraph formats.
|
|---|
| 1067 | *
|
|---|
| 1068 | * -- prclView: rectangle for which formatting should take
|
|---|
| 1069 | * place. When this is called for a screen window,
|
|---|
| 1070 | * this should be the visible area of the window
|
|---|
| 1071 | * (WinQueryWindowRect).
|
|---|
| 1072 | * When this is called with a printer PS, this should
|
|---|
| 1073 | * be the size of a printer page.
|
|---|
| 1074 | *
|
|---|
| 1075 | * This function updates the following:
|
|---|
| 1076 | *
|
|---|
| 1077 | * -- XFORMATDATA.llWords: list of TXVWORD structures,
|
|---|
| 1078 | * holding all the "words" in the text as described
|
|---|
| 1079 | * above. This list can grow very long, but only needs
|
|---|
| 1080 | * to be recalculated when fonts change.
|
|---|
| 1081 | *
|
|---|
| 1082 | * -- XFORMATDATA.llRectangles: list of TXVRECTANGLE
|
|---|
| 1083 | * structures, correlating the words on the words list
|
|---|
| 1084 | * to paint rectangles.
|
|---|
| 1085 | *
|
|---|
| 1086 | * -- XFORMATDATA.szlWorkspace: total width
|
|---|
| 1087 | * and height of the "workspace", i.e. the total space
|
|---|
| 1088 | * needed to display the text (in pels). This might
|
|---|
| 1089 | * be smaller, the same, or larger than prclView,
|
|---|
| 1090 | * depending on whether the text fits into prclView.
|
|---|
| 1091 | *
|
|---|
| 1092 | * When displaying text, you should display scroll bars
|
|---|
| 1093 | * if the workspace is larger than the window (prclView).
|
|---|
| 1094 | *
|
|---|
| 1095 | * When printing, if the workspace is larger than the
|
|---|
| 1096 | * printer page (prclView), you will need to call
|
|---|
| 1097 | * txvPaintText several times for each page.
|
|---|
| 1098 | *
|
|---|
| 1099 | * All coordinates are in world space (PU_PELS).
|
|---|
| 1100 | *
|
|---|
| 1101 | *@@changed V0.9.3 (2000-05-06) [umoeller]: largely rewritten; now handling paragraph and character formats
|
|---|
| 1102 | *@@todo TXVWORDF_GLUEWITHNEXT
|
|---|
| 1103 | */
|
|---|
| 1104 |
|
|---|
| 1105 | VOID txvFormatText(HPS hps, // in: HPS whose font is used for
|
|---|
| 1106 | // calculating text dimensions
|
|---|
| 1107 | PXFORMATDATA pxfd, // in: formatting data
|
|---|
| 1108 | PRECTL prclView, // in: rectangle to format for (window or printer page)
|
|---|
| 1109 | BOOL fFullRecalc) // in: re-calculate word list too? (must be TRUE on the first call)
|
|---|
| 1110 | {
|
|---|
| 1111 | /* ULONG ulWinCX = (prclView->xRight - prclView->xLeft),
|
|---|
| 1112 | ulWinCY = (prclView->yTop - prclView->yBottom); */
|
|---|
| 1113 |
|
|---|
| 1114 | lstClear(&pxfd->llRectangles);
|
|---|
| 1115 | if (fFullRecalc)
|
|---|
| 1116 | lstClear(&pxfd->llWords);
|
|---|
| 1117 |
|
|---|
| 1118 | pxfd->szlWorkspace.cx = 0;
|
|---|
| 1119 | pxfd->szlWorkspace.cy = 0;
|
|---|
| 1120 |
|
|---|
| 1121 | if (pxfd->strViewText.cbAllocated)
|
|---|
| 1122 | {
|
|---|
| 1123 | ULONG ulTextLen = pxfd->strViewText.ulLength;
|
|---|
| 1124 |
|
|---|
| 1125 | FORMATLINEBUF flbuf;
|
|---|
| 1126 | LONG lcidLast = -99,
|
|---|
| 1127 | lPointSizeLast = -99;
|
|---|
| 1128 |
|
|---|
| 1129 | memset(&flbuf, 0, sizeof(flbuf));
|
|---|
| 1130 | // copy default paragraph formatting
|
|---|
| 1131 | memcpy(&flbuf.fmtp, &pxfd->fmtpStandard, sizeof(flbuf.fmtp));
|
|---|
| 1132 | // set font
|
|---|
| 1133 | flbuf.pfmtc = &pxfd->fmtcStandard;
|
|---|
| 1134 | flbuf.lPointSize = pxfd->fmtcStandard.lPointSize;
|
|---|
| 1135 | flbuf.pLastChar = pxfd->strViewText.psz + ulTextLen;
|
|---|
| 1136 |
|
|---|
| 1137 | if (ulTextLen)
|
|---|
| 1138 | {
|
|---|
| 1139 | ULONG cWords = 0;
|
|---|
| 1140 |
|
|---|
| 1141 | if (fFullRecalc)
|
|---|
| 1142 | {
|
|---|
| 1143 | /*
|
|---|
| 1144 | * step 1: create words
|
|---|
| 1145 | *
|
|---|
| 1146 | */
|
|---|
| 1147 |
|
|---|
| 1148 | PSZ pCurrent = pxfd->strViewText.psz;
|
|---|
| 1149 |
|
|---|
| 1150 | // loop until null terminator
|
|---|
| 1151 | while (*pCurrent)
|
|---|
| 1152 | {
|
|---|
| 1153 | PTXVWORD pWord;
|
|---|
| 1154 |
|
|---|
| 1155 | if (flbuf.fBold)
|
|---|
| 1156 | {
|
|---|
| 1157 | if (flbuf.fItalics)
|
|---|
| 1158 | flbuf.pfmtf = &flbuf.pfmtc->fntBoldItalics;
|
|---|
| 1159 | else
|
|---|
| 1160 | flbuf.pfmtf = &flbuf.pfmtc->fntBold;
|
|---|
| 1161 | }
|
|---|
| 1162 | else
|
|---|
| 1163 | if (flbuf.fItalics)
|
|---|
| 1164 | flbuf.pfmtf = &flbuf.pfmtc->fntItalics;
|
|---|
| 1165 | else
|
|---|
| 1166 | flbuf.pfmtf = &flbuf.pfmtc->fntRegular;
|
|---|
| 1167 |
|
|---|
| 1168 | // set font for subsequent calculations,
|
|---|
| 1169 | // if changed (this includes the first call)
|
|---|
| 1170 | if (lcidLast != flbuf.pfmtf->lcid)
|
|---|
| 1171 | {
|
|---|
| 1172 | GpiSetCharSet(hps, flbuf.pfmtf->lcid);
|
|---|
| 1173 | lcidLast = flbuf.pfmtf->lcid;
|
|---|
| 1174 | // force recalc of point size
|
|---|
| 1175 | lPointSizeLast = -99;
|
|---|
| 1176 | }
|
|---|
| 1177 |
|
|---|
| 1178 | if (lPointSizeLast != flbuf.lPointSize)
|
|---|
| 1179 | {
|
|---|
| 1180 | if (flbuf.pfmtf->FontMetrics.fsDefn & FM_DEFN_OUTLINE)
|
|---|
| 1181 | // is outline font:
|
|---|
| 1182 | gpihSetPointSize(hps, flbuf.lPointSize);
|
|---|
| 1183 | lPointSizeLast = flbuf.lPointSize;
|
|---|
| 1184 | }
|
|---|
| 1185 |
|
|---|
| 1186 | if (pWord = CreateWord(hps,
|
|---|
| 1187 | &pCurrent, // advanced to next word
|
|---|
| 1188 | &flbuf))
|
|---|
| 1189 | {
|
|---|
| 1190 | lstAppendItem(&pxfd->llWords, pWord);
|
|---|
| 1191 |
|
|---|
| 1192 | /* {
|
|---|
| 1193 | CHAR szWord[3000];
|
|---|
| 1194 | strhncpy0(szWord, pWord->pStart, min(pWord->cChars, sizeof(szWord)));
|
|---|
| 1195 | _Pmpf(("Found word '%s'", szWord));
|
|---|
| 1196 | } */
|
|---|
| 1197 |
|
|---|
| 1198 | cWords++;
|
|---|
| 1199 |
|
|---|
| 1200 | while (*pCurrent == TXVESC_CHAR) // '\xFF')
|
|---|
| 1201 | {
|
|---|
| 1202 | // handle escapes;
|
|---|
| 1203 | // this advances pCurrent depending on the
|
|---|
| 1204 | // escape sequence length and might append
|
|---|
| 1205 | // another "word" for the escape sequence
|
|---|
| 1206 | // if it's relevant for rectangle correlation
|
|---|
| 1207 | ProcessEscapes(&pCurrent,
|
|---|
| 1208 | pxfd,
|
|---|
| 1209 | &flbuf,
|
|---|
| 1210 | FALSE); // fWordsProcessed
|
|---|
| 1211 | }
|
|---|
| 1212 | }
|
|---|
| 1213 | else
|
|---|
| 1214 | break;
|
|---|
| 1215 | }
|
|---|
| 1216 | } // end if (fFullRecalc)
|
|---|
| 1217 | else
|
|---|
| 1218 | cWords = lstCountItems(&pxfd->llWords);
|
|---|
| 1219 |
|
|---|
| 1220 | /*
|
|---|
| 1221 | * step 2: create rectangles
|
|---|
| 1222 | *
|
|---|
| 1223 | */
|
|---|
| 1224 |
|
|---|
| 1225 | if (cWords)
|
|---|
| 1226 | {
|
|---|
| 1227 | PLISTNODE pWordNode = lstQueryFirstNode(&pxfd->llWords);
|
|---|
| 1228 |
|
|---|
| 1229 | LONG lCurrentYTop = prclView->yTop,
|
|---|
| 1230 | lOrigYTop = lCurrentYTop;
|
|---|
| 1231 |
|
|---|
| 1232 | BOOL fRects2Go = TRUE;
|
|---|
| 1233 |
|
|---|
| 1234 | // space before paragraph; this is reset
|
|---|
| 1235 | // to 0 if we start a new rectangle for
|
|---|
| 1236 | // the same paragraph
|
|---|
| 1237 | ULONG ulYPre = flbuf.fmtp.lSpaceBefore;
|
|---|
| 1238 |
|
|---|
| 1239 | // rectangles loop
|
|---|
| 1240 | while (fRects2Go)
|
|---|
| 1241 | {
|
|---|
| 1242 | BOOL fWords2Go = TRUE;
|
|---|
| 1243 | ULONG ulWordsInThisRect = 0;
|
|---|
| 1244 |
|
|---|
| 1245 | // maximum height of words in this rect
|
|---|
| 1246 | ULONG lWordsMaxCY = 0;
|
|---|
| 1247 |
|
|---|
| 1248 | // start a new rectangle:
|
|---|
| 1249 | PTXVRECTANGLE pRect = (PTXVRECTANGLE)malloc(sizeof(TXVRECTANGLE));
|
|---|
| 1250 | lstInit(&pRect->llWords,
|
|---|
| 1251 | FALSE); // no auto-free; the words are stored in the main
|
|---|
| 1252 | // list also, which is freed
|
|---|
| 1253 | // rectangle's xLeft;
|
|---|
| 1254 | // xRight will be set when we're done with this rectangle
|
|---|
| 1255 | pRect->rcl.xLeft = prclView->xLeft + flbuf.fmtp.lLeftMargin;
|
|---|
| 1256 | if (ulYPre)
|
|---|
| 1257 | // starting new paragraph:
|
|---|
| 1258 | // add first-line offset also
|
|---|
| 1259 | pRect->rcl.xLeft += flbuf.fmtp.lFirstLineMargin;
|
|---|
| 1260 |
|
|---|
| 1261 | // current X pos: start with left of rectangle
|
|---|
| 1262 | flbuf.lXCurrent = pRect->rcl.xLeft;
|
|---|
| 1263 |
|
|---|
| 1264 | // max baseline ofs: set to 0, this will be raised
|
|---|
| 1265 | pRect->ulMaxBaseLineOfs = 0;
|
|---|
| 1266 |
|
|---|
| 1267 | // words-per-rectangle loop;
|
|---|
| 1268 | // we keep adding words to the rectangle until
|
|---|
| 1269 | // a) words no longer fit and word-wrapping is on;
|
|---|
| 1270 | // b) a newline or line feed is found;
|
|---|
| 1271 | // c) the last word has been reached;
|
|---|
| 1272 | while (fWords2Go)
|
|---|
| 1273 | {
|
|---|
| 1274 | PTXVWORD pWordThis = (PTXVWORD)pWordNode->pItemData;
|
|---|
| 1275 | /*
|
|---|
| 1276 | #define TXVWORDF_GLUEWITHNEXT 1 // escape
|
|---|
| 1277 | #define TXVWORDF_LINEBREAK 2 // \n
|
|---|
| 1278 | #define TXVWORDF_LINEFEED 4 // \r
|
|---|
| 1279 | */
|
|---|
| 1280 | BOOL fNextWord = FALSE;
|
|---|
| 1281 |
|
|---|
| 1282 | if (pWordThis->cEscapeCode)
|
|---|
| 1283 | {
|
|---|
| 1284 | // pseudo-word for escape sequence:
|
|---|
| 1285 | // process...
|
|---|
| 1286 | ProcessEscapes((PSZ*)&pWordThis->pStart,
|
|---|
| 1287 | pxfd,
|
|---|
| 1288 | &flbuf,
|
|---|
| 1289 | TRUE);
|
|---|
| 1290 |
|
|---|
| 1291 | // append this sequence only if it's needed
|
|---|
| 1292 | // for painting (list markers etc.)
|
|---|
| 1293 | if (pWordThis->fPaintEscapeWord)
|
|---|
| 1294 | {
|
|---|
| 1295 | pWordThis->lX = flbuf.lXCurrent;
|
|---|
| 1296 | pWordThis->pRectangle = pRect;
|
|---|
| 1297 | lstAppendItem(&pRect->llWords, pWordThis);
|
|---|
| 1298 | ulWordsInThisRect++;
|
|---|
| 1299 | }
|
|---|
| 1300 |
|
|---|
| 1301 | fNextWord = TRUE;
|
|---|
| 1302 | }
|
|---|
| 1303 | else
|
|---|
| 1304 | {
|
|---|
| 1305 | BOOL fWordWrapped = FALSE;
|
|---|
| 1306 |
|
|---|
| 1307 | // not escape sequence, but real word: format...
|
|---|
| 1308 | // is word-wrapping on?
|
|---|
| 1309 | if (flbuf.fmtp.fWordWrap)
|
|---|
| 1310 | {
|
|---|
| 1311 | // yes: check if the word still fits
|
|---|
| 1312 | if ( (flbuf.lXCurrent + pWordThis->ulCXWithSpaces // ###
|
|---|
| 1313 | > prclView->xRight)
|
|---|
| 1314 | // > ulWinCX)
|
|---|
| 1315 | // but always add the first word in the rectangle,
|
|---|
| 1316 | // because otherwise we get infinite loops
|
|---|
| 1317 | && (ulWordsInThisRect > 0)
|
|---|
| 1318 | )
|
|---|
| 1319 | // no:
|
|---|
| 1320 | fWordWrapped = TRUE;
|
|---|
| 1321 | }
|
|---|
| 1322 |
|
|---|
| 1323 | if (fWordWrapped)
|
|---|
| 1324 | // start a new rectangle with the current word:
|
|---|
| 1325 | fWords2Go = FALSE;
|
|---|
| 1326 | // and do _not_ advance to the next word,
|
|---|
| 1327 | // but start with this word for the next
|
|---|
| 1328 | // rectangle...
|
|---|
| 1329 | else
|
|---|
| 1330 | {
|
|---|
| 1331 | // add this word to the rectangle:
|
|---|
| 1332 |
|
|---|
| 1333 | // store current X pos in word
|
|---|
| 1334 | pWordThis->lX = flbuf.lXCurrent;
|
|---|
| 1335 |
|
|---|
| 1336 | // increase current X pos by word width
|
|---|
| 1337 | flbuf.lXCurrent += pWordThis->ulCXWithSpaces;
|
|---|
| 1338 |
|
|---|
| 1339 | // store word in rectangle
|
|---|
| 1340 | pWordThis->pRectangle = pRect;
|
|---|
| 1341 | lstAppendItem(&pRect->llWords, pWordThis);
|
|---|
| 1342 | // @@todo memory leak right here!!!
|
|---|
| 1343 | ulWordsInThisRect++;
|
|---|
| 1344 |
|
|---|
| 1345 | // store highest word width found for this rect
|
|---|
| 1346 | if (pWordThis->ulCY > lWordsMaxCY)
|
|---|
| 1347 | lWordsMaxCY = pWordThis->ulCY;
|
|---|
| 1348 |
|
|---|
| 1349 | // store highest base line ofs found for this rect
|
|---|
| 1350 | if (pWordThis->ulBaseLineOfs > pRect->ulMaxBaseLineOfs)
|
|---|
| 1351 | pRect->ulMaxBaseLineOfs = pWordThis->ulBaseLineOfs;
|
|---|
| 1352 |
|
|---|
| 1353 | // go for next word in any case
|
|---|
| 1354 | fNextWord = TRUE;
|
|---|
| 1355 | } // end if (!fBreakThisWord)
|
|---|
| 1356 |
|
|---|
| 1357 | // now check: add more words to this rectangle?
|
|---|
| 1358 | if ( (pWordThis->ulFlags == TXVWORDF_LINEBREAK)
|
|---|
| 1359 | // no if linebreak found
|
|---|
| 1360 | || (pWordThis->ulFlags == TXVWORDF_LINEFEED)
|
|---|
| 1361 | // no if linefeed found
|
|---|
| 1362 | || (!fWords2Go)
|
|---|
| 1363 | // no if we're out of words or
|
|---|
| 1364 | // word-break was forced
|
|---|
| 1365 | )
|
|---|
| 1366 | {
|
|---|
| 1367 | // no: finish up this rectangle...
|
|---|
| 1368 |
|
|---|
| 1369 | // xLeft has been set on top
|
|---|
| 1370 | pRect->rcl.xRight = flbuf.lXCurrent;
|
|---|
| 1371 | pRect->rcl.yTop = lCurrentYTop - ulYPre;
|
|---|
| 1372 | pRect->rcl.yBottom = pRect->rcl.yTop - lWordsMaxCY;
|
|---|
| 1373 |
|
|---|
| 1374 | // decrease current y top for next line
|
|---|
| 1375 | lCurrentYTop = pRect->rcl.yBottom;
|
|---|
| 1376 | if (!fRects2Go)
|
|---|
| 1377 | // we're done completely:
|
|---|
| 1378 | // add another one
|
|---|
| 1379 | lCurrentYTop -= lWordsMaxCY;
|
|---|
| 1380 |
|
|---|
| 1381 | if (fWordWrapped)
|
|---|
| 1382 | // starting with wrapped word in next line:
|
|---|
| 1383 | ulYPre = 0;
|
|---|
| 1384 | else
|
|---|
| 1385 | if (pWordThis->ulFlags == TXVWORDF_LINEFEED)
|
|---|
| 1386 | ulYPre = 0;
|
|---|
| 1387 | else if (pWordThis->ulFlags == TXVWORDF_LINEBREAK)
|
|---|
| 1388 | {
|
|---|
| 1389 | // line break:
|
|---|
| 1390 | // set y-pre for next loop
|
|---|
| 1391 | ulYPre = flbuf.fmtp.lSpaceBefore;
|
|---|
| 1392 | // and add paragraph post-y
|
|---|
| 1393 | lCurrentYTop -= flbuf.fmtp.lSpaceAfter;
|
|---|
| 1394 | }
|
|---|
| 1395 |
|
|---|
| 1396 | // update x extents
|
|---|
| 1397 | if (pRect->rcl.xRight > pxfd->szlWorkspace.cx)
|
|---|
| 1398 | pxfd->szlWorkspace.cx = pRect->rcl.xRight;
|
|---|
| 1399 |
|
|---|
| 1400 | // and quit the inner loop
|
|---|
| 1401 | fWords2Go = FALSE;
|
|---|
| 1402 | } // end finish up rectangle
|
|---|
| 1403 | } // end else if (pWordThis->fIsEscapeSequence)
|
|---|
| 1404 |
|
|---|
| 1405 | if (fNextWord)
|
|---|
| 1406 | {
|
|---|
| 1407 | pWordNode = pWordNode->pNext;
|
|---|
| 1408 | if (!pWordNode)
|
|---|
| 1409 | {
|
|---|
| 1410 | // no more to go:
|
|---|
| 1411 | // quit
|
|---|
| 1412 | fWords2Go = FALSE;
|
|---|
| 1413 | fRects2Go = FALSE;
|
|---|
| 1414 | }
|
|---|
| 1415 | }
|
|---|
| 1416 | } // end while (fWords2Go)
|
|---|
| 1417 |
|
|---|
| 1418 | // store rectangle
|
|---|
| 1419 | lstAppendItem(&pxfd->llRectangles, pRect);
|
|---|
| 1420 | }
|
|---|
| 1421 |
|
|---|
| 1422 | // lCurrentYTop now has the bottommost point we've used;
|
|---|
| 1423 | // store this as workspace (this might be negative)
|
|---|
| 1424 | pxfd->szlWorkspace.cy = lOrigYTop - lCurrentYTop;
|
|---|
| 1425 | }
|
|---|
| 1426 | }
|
|---|
| 1427 | }
|
|---|
| 1428 | }
|
|---|
| 1429 |
|
|---|
| 1430 | /* ******************************************************************
|
|---|
| 1431 | *
|
|---|
| 1432 | * Device-independent text painting
|
|---|
| 1433 | *
|
|---|
| 1434 | ********************************************************************/
|
|---|
| 1435 |
|
|---|
| 1436 | /*
|
|---|
| 1437 | *@@ DrawListMarker:
|
|---|
| 1438 | *
|
|---|
| 1439 | *@@added V0.9.3 (2000-05-17) [umoeller]
|
|---|
| 1440 | */
|
|---|
| 1441 |
|
|---|
| 1442 | STATIC VOID DrawListMarker(HPS hps,
|
|---|
| 1443 | PRECTL prclLine, // current line rectangle
|
|---|
| 1444 | PTXVWORD pWordThis, // current word
|
|---|
| 1445 | LONG lViewXOfs) // in: x offset to paint; 0 means rightmost
|
|---|
| 1446 | {
|
|---|
| 1447 | POINTL ptl;
|
|---|
| 1448 |
|
|---|
| 1449 | ULONG ulBulletSize = pWordThis->lPointSize * 2 / 3; // 2/3 of point size
|
|---|
| 1450 |
|
|---|
| 1451 | ARCPARAMS arcp = {1, 1, 0, 0};
|
|---|
| 1452 |
|
|---|
| 1453 | // pWordThis->pStart points to the \xFF character;
|
|---|
| 1454 | // next is the "marker" escape (\x23),
|
|---|
| 1455 | // next is the marker type
|
|---|
| 1456 | CHAR cBulletType = *((pWordThis->pStart) + 2) ;
|
|---|
| 1457 |
|
|---|
| 1458 | switch (cBulletType)
|
|---|
| 1459 | {
|
|---|
| 1460 | case 2: // square (filled box)
|
|---|
| 1461 | ptl.x = pWordThis->lX - lViewXOfs;
|
|---|
| 1462 | // center bullet vertically
|
|---|
| 1463 | ptl.y = prclLine->yBottom
|
|---|
| 1464 | + ( (prclLine->yTop - prclLine->yBottom) // height
|
|---|
| 1465 | - ulBulletSize
|
|---|
| 1466 | ) / 2;
|
|---|
| 1467 |
|
|---|
| 1468 | GpiMove(hps, &ptl);
|
|---|
| 1469 | ptl.x += ulBulletSize;
|
|---|
| 1470 | ptl.y += ulBulletSize;
|
|---|
| 1471 | GpiBox(hps, DRO_FILL, &ptl, 0, 0);
|
|---|
| 1472 | break;
|
|---|
| 1473 |
|
|---|
| 1474 | default: // case 1: // disc (filled circle)
|
|---|
| 1475 | ptl.x = pWordThis->lX - lViewXOfs;
|
|---|
| 1476 | // center bullet vertically;
|
|---|
| 1477 | // the arc is drawn with the current position in its center
|
|---|
| 1478 | ptl.y = prclLine->yBottom
|
|---|
| 1479 | + ( (prclLine->yTop - prclLine->yBottom) // height
|
|---|
| 1480 | / 2
|
|---|
| 1481 | );
|
|---|
| 1482 |
|
|---|
| 1483 | GpiSetArcParams(hps, &arcp);
|
|---|
| 1484 | GpiMove(hps, &ptl);
|
|---|
| 1485 | GpiFullArc(hps,
|
|---|
| 1486 | (cBulletType == 3)
|
|---|
| 1487 | ? DRO_OUTLINE
|
|---|
| 1488 | : DRO_FILL,
|
|---|
| 1489 | MAKEFIXED(ulBulletSize / 2, // radius!
|
|---|
| 1490 | 0));
|
|---|
| 1491 | break;
|
|---|
| 1492 |
|
|---|
| 1493 | }
|
|---|
| 1494 | }
|
|---|
| 1495 |
|
|---|
| 1496 | /*
|
|---|
| 1497 | *@@ txvPaintText:
|
|---|
| 1498 | * device-independent function for painting.
|
|---|
| 1499 | * This can only be called after the text has
|
|---|
| 1500 | * been formatted (using txvFormatText).
|
|---|
| 1501 | *
|
|---|
| 1502 | * This only paints rectangles which are within
|
|---|
| 1503 | * prcl2Paint.
|
|---|
| 1504 | *
|
|---|
| 1505 | * -- For WM_PAINT, set this to the
|
|---|
| 1506 | * update rectangle, and set fPaintHalfLines
|
|---|
| 1507 | * to TRUE.
|
|---|
| 1508 | *
|
|---|
| 1509 | * -- For printing, set this to the page rectangle,
|
|---|
| 1510 | * and set fPaintHalfLines to FALSE.
|
|---|
| 1511 | *
|
|---|
| 1512 | * All coordinates are in world space (PU_PELS).
|
|---|
| 1513 | *
|
|---|
| 1514 | *@@changed V0.9.3 (2000-05-05) [umoeller]: fixed wrong visible lines calculations; great speedup painting!
|
|---|
| 1515 | *@@changed V0.9.3 (2000-05-06) [umoeller]: now using gpihCharStringPosAt
|
|---|
| 1516 | */
|
|---|
| 1517 |
|
|---|
| 1518 | BOOL txvPaintText(HAB hab,
|
|---|
| 1519 | HPS hps, // in: window or printer PS
|
|---|
| 1520 | PXFORMATDATA pxfd,
|
|---|
| 1521 | PRECTL prcl2Paint, // in: invalid rectangle to be drawn,
|
|---|
| 1522 | // can be NULL to paint all
|
|---|
| 1523 | LONG lViewXOfs, // in: x offset to paint; 0 means rightmost
|
|---|
| 1524 | PLONG plViewYOfs, // in: y offset to paint; 0 means _top_most;
|
|---|
| 1525 | // out: y offset which should be passed to next call
|
|---|
| 1526 | // (if TRUE is returned and fPaintHalfLines == FALSE)
|
|---|
| 1527 | BOOL fPaintHalfLines, // in: if FALSE, lines which do not fully fit on
|
|---|
| 1528 | // the page are dropped (useful for printing)
|
|---|
| 1529 | PULONG pulLineIndex) // in: line to start painting with;
|
|---|
| 1530 | // out: next line to paint, if any
|
|---|
| 1531 | // (if TRUE is returned and fPaintHalfLines == FALSE)
|
|---|
| 1532 | {
|
|---|
| 1533 | BOOL brc = FALSE,
|
|---|
| 1534 | fAnyLinesPainted = FALSE;
|
|---|
| 1535 | ULONG ulCurrentLineIndex = *pulLineIndex;
|
|---|
| 1536 | // LONG lViewYOfsSaved = *plViewYOfs;
|
|---|
| 1537 | PLISTNODE pRectNode = lstNodeFromIndex(&pxfd->llRectangles,
|
|---|
| 1538 | ulCurrentLineIndex);
|
|---|
| 1539 |
|
|---|
| 1540 | LONG lcidLast = -99;
|
|---|
| 1541 | LONG lPointSizeLast = -99;
|
|---|
| 1542 |
|
|---|
| 1543 | while (pRectNode)
|
|---|
| 1544 | {
|
|---|
| 1545 | PTXVRECTANGLE pLineRcl = (PTXVRECTANGLE)pRectNode->pItemData;
|
|---|
| 1546 | BOOL fPaintThis = FALSE;
|
|---|
| 1547 |
|
|---|
| 1548 | // compose rectangle to draw for this line
|
|---|
| 1549 | RECTL rclLine;
|
|---|
| 1550 | rclLine.xLeft = pLineRcl->rcl.xLeft - lViewXOfs;
|
|---|
| 1551 | rclLine.xRight = pLineRcl->rcl.xRight - lViewXOfs;
|
|---|
| 1552 | rclLine.yBottom = pLineRcl->rcl.yBottom + *plViewYOfs;
|
|---|
| 1553 | rclLine.yTop = pLineRcl->rcl.yTop + *plViewYOfs;
|
|---|
| 1554 |
|
|---|
| 1555 | /* if (pmpf)
|
|---|
| 1556 | {
|
|---|
| 1557 | CHAR szTemp[100];
|
|---|
| 1558 | ULONG cb = min(pLineRcl->cLineChars, 99);
|
|---|
| 1559 | strhncpy0(szTemp, pLineRcl->pStartOfLine, cb);
|
|---|
| 1560 |
|
|---|
| 1561 | _Pmpf(("Checking line %d: '%s'",
|
|---|
| 1562 | ulCurrentLineIndex,
|
|---|
| 1563 | szTemp));
|
|---|
| 1564 |
|
|---|
| 1565 | _Pmpf((" (yB stored %d -> in HPS %d against win yB %d)",
|
|---|
| 1566 | pLineRcl->rcl.yBottom,
|
|---|
| 1567 | rclLine.yBottom,
|
|---|
| 1568 | prcl2Paint->yBottom));
|
|---|
| 1569 | } */
|
|---|
| 1570 |
|
|---|
| 1571 | if (prcl2Paint == NULL)
|
|---|
| 1572 | // draw all:
|
|---|
| 1573 | fPaintThis = TRUE;
|
|---|
| 1574 | else
|
|---|
| 1575 | {
|
|---|
| 1576 | BOOL fBottomInPaint = ( (rclLine.yBottom >= prcl2Paint->yBottom)
|
|---|
| 1577 | && (rclLine.yBottom <= prcl2Paint->yTop)
|
|---|
| 1578 | );
|
|---|
| 1579 | BOOL fTopInPaint = ( (rclLine.yTop >= prcl2Paint->yBottom)
|
|---|
| 1580 | && (rclLine.yTop <= prcl2Paint->yTop)
|
|---|
| 1581 | );
|
|---|
| 1582 |
|
|---|
| 1583 | if ((fBottomInPaint) && (fTopInPaint))
|
|---|
| 1584 | // both in update rect:
|
|---|
| 1585 | fPaintThis = TRUE;
|
|---|
| 1586 | else
|
|---|
| 1587 | if (fPaintHalfLines)
|
|---|
| 1588 | {
|
|---|
| 1589 | if ((fBottomInPaint) || (fTopInPaint))
|
|---|
| 1590 | // only one in update rect:
|
|---|
| 1591 | fPaintThis = TRUE;
|
|---|
| 1592 | else
|
|---|
| 1593 | // now, for very small update rectangles,
|
|---|
| 1594 | // especially with slow scrolling,
|
|---|
| 1595 | // we can have the case that the paint rectangle
|
|---|
| 1596 | // is only a few pixels high so that the top of
|
|---|
| 1597 | // the line is above the repaint, and the bottom
|
|---|
| 1598 | // of the line is below it!
|
|---|
| 1599 | if ( (rclLine.yTop >= prcl2Paint->yTop)
|
|---|
| 1600 | && (rclLine.yBottom <= prcl2Paint->yBottom)
|
|---|
| 1601 | )
|
|---|
| 1602 | fPaintThis = TRUE;
|
|---|
| 1603 | }
|
|---|
| 1604 | }
|
|---|
| 1605 |
|
|---|
| 1606 | if (fPaintThis)
|
|---|
| 1607 | {
|
|---|
| 1608 | // rectangle invalid: paint this rectangle
|
|---|
| 1609 | // by going thru the member words
|
|---|
| 1610 | PLISTNODE pWordNode = lstQueryFirstNode(&pLineRcl->llWords);
|
|---|
| 1611 |
|
|---|
| 1612 | POINTL ptlStart;
|
|---|
| 1613 |
|
|---|
| 1614 | while (pWordNode)
|
|---|
| 1615 | {
|
|---|
| 1616 | PTXVWORD pWordThis = (PTXVWORD)pWordNode->pItemData;
|
|---|
| 1617 | ULONG flChar = pWordThis->flChar;
|
|---|
| 1618 |
|
|---|
| 1619 | if (pWordThis->pcszLinkTarget) // V0.9.20 (2002-08-10) [umoeller]
|
|---|
| 1620 | flChar |= CHS_UNDERSCORE;
|
|---|
| 1621 |
|
|---|
| 1622 | // x start: this word's X coordinate
|
|---|
| 1623 | ptlStart.x = pWordThis->lX - lViewXOfs;
|
|---|
| 1624 | // y start: bottom line of rectangle plus highest
|
|---|
| 1625 | // base line offset found in all words (format step 2)
|
|---|
| 1626 | ptlStart.y = rclLine.yBottom + pLineRcl->ulMaxBaseLineOfs;
|
|---|
| 1627 | // pWordThis->ulBaseLineOfs;
|
|---|
| 1628 |
|
|---|
| 1629 | // set font for subsequent calculations,
|
|---|
| 1630 | // if changed (this includes the first call)
|
|---|
| 1631 | if (lcidLast != pWordThis->lcid)
|
|---|
| 1632 | {
|
|---|
| 1633 | GpiSetCharSet(hps, pWordThis->lcid);
|
|---|
| 1634 | lcidLast = pWordThis->lcid;
|
|---|
| 1635 | // force recalc of point size
|
|---|
| 1636 | lPointSizeLast = -99;
|
|---|
| 1637 | }
|
|---|
| 1638 |
|
|---|
| 1639 | if (lPointSizeLast != pWordThis->lPointSize)
|
|---|
| 1640 | {
|
|---|
| 1641 | if (pWordThis->lPointSize)
|
|---|
| 1642 | // is outline font:
|
|---|
| 1643 | gpihSetPointSize(hps, pWordThis->lPointSize);
|
|---|
| 1644 | lPointSizeLast = pWordThis->lPointSize;
|
|---|
| 1645 | }
|
|---|
| 1646 |
|
|---|
| 1647 | if (!pWordThis->cEscapeCode)
|
|---|
| 1648 | // regular word:
|
|---|
| 1649 | gpihCharStringPosAt(hps,
|
|---|
| 1650 | &ptlStart,
|
|---|
| 1651 | &rclLine,
|
|---|
| 1652 | flChar,
|
|---|
| 1653 | pWordThis->cChars,
|
|---|
| 1654 | (PSZ)pWordThis->pStart);
|
|---|
| 1655 | else
|
|---|
| 1656 | {
|
|---|
| 1657 | // check escape code
|
|---|
| 1658 | switch (pWordThis->cEscapeCode)
|
|---|
| 1659 | {
|
|---|
| 1660 | case 0x23:
|
|---|
| 1661 | // escape to be painted:
|
|---|
| 1662 | DrawListMarker(hps,
|
|---|
| 1663 | &rclLine,
|
|---|
| 1664 | pWordThis,
|
|---|
| 1665 | lViewXOfs);
|
|---|
| 1666 | break;
|
|---|
| 1667 | }
|
|---|
| 1668 | }
|
|---|
| 1669 |
|
|---|
| 1670 | // ptlStart.x += pWordThis->ulCXWithSpaces;
|
|---|
| 1671 |
|
|---|
| 1672 | fAnyLinesPainted = TRUE;
|
|---|
| 1673 | pWordNode = pWordNode->pNext;
|
|---|
| 1674 | }
|
|---|
| 1675 |
|
|---|
| 1676 | /* {
|
|---|
| 1677 | LONG lColor = GpiQueryColor(hps);
|
|---|
| 1678 | POINTL ptl2;
|
|---|
| 1679 | GpiSetColor(hps, RGBCOL_RED);
|
|---|
| 1680 | ptl2.x = rclLine.xLeft;
|
|---|
| 1681 | ptl2.y = rclLine.yBottom;
|
|---|
| 1682 | GpiMove(hps, &ptl2);
|
|---|
| 1683 | ptl2.x = rclLine.xRight;
|
|---|
| 1684 | ptl2.y = rclLine.yTop;
|
|---|
| 1685 | GpiBox(hps,
|
|---|
| 1686 | DRO_OUTLINE,
|
|---|
| 1687 | &ptl2,
|
|---|
| 1688 | 0, 0);
|
|---|
| 1689 | GpiSetColor(hps, lColor);
|
|---|
| 1690 | } */
|
|---|
| 1691 |
|
|---|
| 1692 | }
|
|---|
| 1693 | else
|
|---|
| 1694 | {
|
|---|
| 1695 | // this line is no longer fully visible:
|
|---|
| 1696 |
|
|---|
| 1697 | if (fAnyLinesPainted)
|
|---|
| 1698 | {
|
|---|
| 1699 | // we had painted lines already:
|
|---|
| 1700 | // this means that all the following lines are
|
|---|
| 1701 | // too far below the window, so quit
|
|---|
| 1702 | /* if (pmpf)
|
|---|
| 1703 | _Pmpf(("Quitting with line %d (xL = %d yB = %d)",
|
|---|
| 1704 | ulCurrentLineIndex, rclLine.xLeft, rclLine.yBottom)); */
|
|---|
| 1705 |
|
|---|
| 1706 | *pulLineIndex = ulCurrentLineIndex;
|
|---|
| 1707 | if (pRectNode->pNext)
|
|---|
| 1708 | {
|
|---|
| 1709 | // another line to paint:
|
|---|
| 1710 | PTXVRECTANGLE pLineRcl2 = (PTXVRECTANGLE)pRectNode->pNext->pItemData;
|
|---|
| 1711 | // return TRUE
|
|---|
| 1712 | brc = TRUE;
|
|---|
| 1713 | // and set *plViewYOfs to the top of
|
|---|
| 1714 | // the next line, which wasn't visible
|
|---|
| 1715 | // on the page any more
|
|---|
| 1716 | *plViewYOfs = pLineRcl2->rcl.yTop + *plViewYOfs;
|
|---|
| 1717 | }
|
|---|
| 1718 | break;
|
|---|
| 1719 | }
|
|---|
| 1720 | // else no lines painted yet:
|
|---|
| 1721 | // go for next node, because we're still above the visible window
|
|---|
| 1722 | }
|
|---|
| 1723 |
|
|---|
| 1724 | // next line
|
|---|
| 1725 | pRectNode = pRectNode->pNext;
|
|---|
| 1726 | // raise index to return
|
|---|
| 1727 | ulCurrentLineIndex++;
|
|---|
| 1728 | }
|
|---|
| 1729 |
|
|---|
| 1730 | if (!fAnyLinesPainted)
|
|---|
| 1731 | brc = FALSE;
|
|---|
| 1732 |
|
|---|
| 1733 | return brc;
|
|---|
| 1734 | }
|
|---|
| 1735 |
|
|---|
| 1736 | /*
|
|---|
| 1737 | *@@ txvFindWordFromPoint:
|
|---|
| 1738 | * returns the list node of the word under the
|
|---|
| 1739 | * given point. The list node is from the global
|
|---|
| 1740 | * words list in pxfd.
|
|---|
| 1741 | *
|
|---|
| 1742 | *@@added V0.9.3 (2000-05-18) [umoeller]
|
|---|
| 1743 | */
|
|---|
| 1744 |
|
|---|
| 1745 | PLISTNODE txvFindWordFromPoint(PXFORMATDATA pxfd,
|
|---|
| 1746 | PPOINTL pptl)
|
|---|
| 1747 | {
|
|---|
| 1748 | PLISTNODE pWordNodeFound = NULL;
|
|---|
| 1749 |
|
|---|
| 1750 | PLISTNODE pRectangleNode = lstQueryFirstNode(&pxfd->llRectangles);
|
|---|
| 1751 | while ((pRectangleNode) && (!pWordNodeFound))
|
|---|
| 1752 | {
|
|---|
| 1753 | PTXVRECTANGLE prclThis = (PTXVRECTANGLE)pRectangleNode->pItemData;
|
|---|
| 1754 | if ( (pptl->x >= prclThis->rcl.xLeft)
|
|---|
| 1755 | && (pptl->x <= prclThis->rcl.xRight)
|
|---|
| 1756 | && (pptl->y >= prclThis->rcl.yBottom)
|
|---|
| 1757 | && (pptl->y <= prclThis->rcl.yTop)
|
|---|
| 1758 | )
|
|---|
| 1759 | {
|
|---|
| 1760 | // cool, we found the rectangle:
|
|---|
| 1761 | // now go thru the words in this rectangle
|
|---|
| 1762 | PLISTNODE pWordNode = lstQueryFirstNode(&prclThis->llWords);
|
|---|
| 1763 | while (pWordNode)
|
|---|
| 1764 | {
|
|---|
| 1765 | PTXVWORD pWordThis = (PTXVWORD)pWordNode->pItemData;
|
|---|
| 1766 |
|
|---|
| 1767 | if ( (pptl->x >= pWordThis->lX)
|
|---|
| 1768 | && (pptl->x <= pWordThis->lX + pWordThis->ulCXWithSpaces)
|
|---|
| 1769 | )
|
|---|
| 1770 | {
|
|---|
| 1771 | pWordNodeFound = pWordNode;
|
|---|
| 1772 | break;
|
|---|
| 1773 | }
|
|---|
| 1774 | pWordNode = pWordNode->pNext;
|
|---|
| 1775 | }
|
|---|
| 1776 | }
|
|---|
| 1777 | pRectangleNode = pRectangleNode->pNext;
|
|---|
| 1778 | }
|
|---|
| 1779 |
|
|---|
| 1780 | return pWordNodeFound;
|
|---|
| 1781 | }
|
|---|
| 1782 |
|
|---|
| 1783 | /*
|
|---|
| 1784 | *@@ txvFindWordFromAnchor:
|
|---|
| 1785 | * returns the list node from the global words list
|
|---|
| 1786 | * BEFORE the word which represents the escape sequence
|
|---|
| 1787 | * containing the specified anchor name.
|
|---|
| 1788 | *
|
|---|
| 1789 | *@@added V0.9.4 (2000-06-12) [umoeller]
|
|---|
| 1790 | */
|
|---|
| 1791 |
|
|---|
| 1792 | PLISTNODE txvFindWordFromAnchor(PXFORMATDATA pxfd,
|
|---|
| 1793 | const char *pszAnchorName)
|
|---|
| 1794 | {
|
|---|
| 1795 | PLISTNODE pNodeFound = NULL;
|
|---|
| 1796 |
|
|---|
| 1797 | ULONG cbAnchorName = strlen(pszAnchorName);
|
|---|
| 1798 |
|
|---|
| 1799 | PLISTNODE pWordNode = lstQueryFirstNode(&pxfd->llWords);
|
|---|
| 1800 | while ((pWordNode) && (!pNodeFound))
|
|---|
| 1801 | {
|
|---|
| 1802 | PTXVWORD pWordThis = (PTXVWORD)pWordNode->pItemData;
|
|---|
| 1803 | if (pWordThis->cEscapeCode == 7)
|
|---|
| 1804 | {
|
|---|
| 1805 | // this word is an anchor escape sequence:
|
|---|
| 1806 | if (strnicmp(pszAnchorName, (pWordThis->pStart + 2), cbAnchorName) == 0)
|
|---|
| 1807 | {
|
|---|
| 1808 | // matches: check length
|
|---|
| 1809 | if (*(pWordThis->pStart + 2 + cbAnchorName) == (char)0xFF)
|
|---|
| 1810 | // OK:
|
|---|
| 1811 | pNodeFound = pWordNode;
|
|---|
| 1812 | }
|
|---|
| 1813 | }
|
|---|
| 1814 |
|
|---|
| 1815 | pWordNode = pWordNode ->pNext;
|
|---|
| 1816 | }
|
|---|
| 1817 |
|
|---|
| 1818 | if (pNodeFound)
|
|---|
| 1819 | {
|
|---|
| 1820 | // anchor found:
|
|---|
| 1821 | // go backwords in word list until we find a "real" word
|
|---|
| 1822 | // which is no escape sequence
|
|---|
| 1823 | while (pNodeFound)
|
|---|
| 1824 | {
|
|---|
| 1825 | PTXVWORD pWordThis = (PTXVWORD)pNodeFound->pItemData;
|
|---|
| 1826 | if (pWordThis->cEscapeCode)
|
|---|
| 1827 | pNodeFound = pNodeFound->pPrevious;
|
|---|
| 1828 | else
|
|---|
| 1829 | break;
|
|---|
| 1830 | }
|
|---|
| 1831 | }
|
|---|
| 1832 |
|
|---|
| 1833 | return pNodeFound;
|
|---|
| 1834 | }
|
|---|
| 1835 |
|
|---|
| 1836 | /* ******************************************************************
|
|---|
| 1837 | *
|
|---|
| 1838 | * Window-dependent functions
|
|---|
| 1839 | *
|
|---|
| 1840 | ********************************************************************/
|
|---|
| 1841 |
|
|---|
| 1842 | #define QWL_PRIVATE 4 // V0.9.20 (2002-08-10) [umoeller]
|
|---|
| 1843 |
|
|---|
| 1844 | /*
|
|---|
| 1845 | *@@ TEXTVIEWWINDATA:
|
|---|
| 1846 | * view control-internal structure, stored in
|
|---|
| 1847 | * QWL_PRIVATE at fnwpTextView.
|
|---|
| 1848 | * This is device-dependent on the text view
|
|---|
| 1849 | * window.
|
|---|
| 1850 | */
|
|---|
| 1851 |
|
|---|
| 1852 | typedef struct _TEXTVIEWWINDATA
|
|---|
| 1853 | {
|
|---|
| 1854 | HAB hab; // anchor block (for speed)
|
|---|
| 1855 |
|
|---|
| 1856 | HDC hdc;
|
|---|
| 1857 | HPS hps;
|
|---|
| 1858 |
|
|---|
| 1859 | ULONG flStyle; // window style flags copied on WM_CREATE
|
|---|
| 1860 | // V0.9.20 (2002-08-10) [umoeller]
|
|---|
| 1861 |
|
|---|
| 1862 | LONG lBackColor,
|
|---|
| 1863 | lForeColor;
|
|---|
| 1864 |
|
|---|
| 1865 | XTEXTVIEWCDATA cdata; // control data, as passed to WM_CREATE
|
|---|
| 1866 |
|
|---|
| 1867 | XFORMATDATA xfd;
|
|---|
| 1868 |
|
|---|
| 1869 | SCROLLABLEWINDOW scrw; // V1.0.1 (2003-01-25) [umoeller]
|
|---|
| 1870 |
|
|---|
| 1871 | // HWND hwndVScroll, // vertical scroll bar
|
|---|
| 1872 | // hwndHScroll; // horizontal scroll bar
|
|---|
| 1873 |
|
|---|
| 1874 | BOOL fVScrollVisible, // TRUE if vscroll is currently used
|
|---|
| 1875 | fHScrollVisible; // TRUE if hscroll is currently used
|
|---|
| 1876 |
|
|---|
| 1877 | RECTL rclViewReal, // window rect as returned by WinQueryWindowRect
|
|---|
| 1878 | // (top right point is inclusive!)
|
|---|
| 1879 | rclViewPaint, // same as rclViewReal, but excluding scroll bars
|
|---|
| 1880 | rclViewText; // same as rclViewPaint, but excluding cdata borders
|
|---|
| 1881 |
|
|---|
| 1882 | // LONG lViewXOfs, // pixels that we have scrolled to the RIGHT; 0 means very left
|
|---|
| 1883 | // lViewYOfs; // pixels that we have scrolled to the BOTTOM; 0 means very top
|
|---|
| 1884 |
|
|---|
| 1885 | BOOL fAcceptsPresParamsNow; // TRUE after first WM_PAINT
|
|---|
| 1886 |
|
|---|
| 1887 | // anchor clicking
|
|---|
| 1888 | PLISTNODE pWordNodeFirstInAnchor; // points to first word which belongs to anchor
|
|---|
| 1889 | // USHORT usLastAnchorClicked; // last anchor which was clicked (1-0xFFFF)
|
|---|
| 1890 | PCSZ pcszLastLinkClicked; // last link that was clicked (points into llLinks)
|
|---|
| 1891 | // V0.9.20 (2002-08-10) [umoeller]
|
|---|
| 1892 |
|
|---|
| 1893 | } TEXTVIEWWINDATA, *PTEXTVIEWWINDATA;
|
|---|
| 1894 |
|
|---|
| 1895 | /*
|
|---|
| 1896 | *@@ UpdateTextViewPresData:
|
|---|
| 1897 | * called from WM_CREATE and WM_PRESPARAMCHANGED
|
|---|
| 1898 | * in fnwpTextView to update the TEXTVIEWWINDATA
|
|---|
| 1899 | * from the window's presparams. This calls
|
|---|
| 1900 | * txvSetDefaultFormat in turn.
|
|---|
| 1901 | */
|
|---|
| 1902 |
|
|---|
| 1903 | STATIC VOID UpdateTextViewPresData(HWND hwndTextView,
|
|---|
| 1904 | PTEXTVIEWWINDATA ptxvd)
|
|---|
| 1905 | {
|
|---|
| 1906 | PSZ pszFont;
|
|---|
| 1907 | ptxvd->lBackColor = winhQueryPresColor(hwndTextView,
|
|---|
| 1908 | PP_BACKGROUNDCOLOR,
|
|---|
| 1909 | FALSE, // no inherit
|
|---|
| 1910 | SYSCLR_DIALOGBACKGROUND);
|
|---|
| 1911 | ptxvd->lForeColor = winhQueryPresColor(hwndTextView,
|
|---|
| 1912 | PP_FOREGROUNDCOLOR,
|
|---|
| 1913 | FALSE, // no inherit
|
|---|
| 1914 | SYSCLR_WINDOWSTATICTEXT);
|
|---|
| 1915 |
|
|---|
| 1916 | if ((pszFont = winhQueryWindowFont(hwndTextView)))
|
|---|
| 1917 | {
|
|---|
| 1918 | ULONG ulSize;
|
|---|
| 1919 | PSZ pszFaceName;
|
|---|
| 1920 | // _Pmpf(("font: %s", pszFont));
|
|---|
| 1921 | if (gpihSplitPresFont(pszFont,
|
|---|
| 1922 | &ulSize,
|
|---|
| 1923 | &pszFaceName))
|
|---|
| 1924 | {
|
|---|
| 1925 | SetFormatFont(ptxvd->hps,
|
|---|
| 1926 | &ptxvd->xfd.fmtcStandard,
|
|---|
| 1927 | ulSize,
|
|---|
| 1928 | pszFaceName);
|
|---|
| 1929 | }
|
|---|
| 1930 | free(pszFont);
|
|---|
| 1931 | }
|
|---|
| 1932 | }
|
|---|
| 1933 |
|
|---|
| 1934 | /*
|
|---|
| 1935 | *@@ AdjustViewRects:
|
|---|
| 1936 | * updates the internal size-dependent structures
|
|---|
| 1937 | * and positions the scroll bars.
|
|---|
| 1938 | *
|
|---|
| 1939 | * This is device-dependent for the text view
|
|---|
| 1940 | * control and must be called before FormatText2Screen
|
|---|
| 1941 | * so that the view rectangles get calculated right.
|
|---|
| 1942 | *
|
|---|
| 1943 | * Required input in TEXTVIEWWINDATA:
|
|---|
| 1944 | *
|
|---|
| 1945 | * -- rclViewReal: the actual window dimensions.
|
|---|
| 1946 | *
|
|---|
| 1947 | * -- cdata: control data.
|
|---|
| 1948 | *
|
|---|
| 1949 | * Output from this function in TEXTVIEWWINDATA:
|
|---|
| 1950 | *
|
|---|
| 1951 | * -- rclViewPaint: the paint subrectangle (which
|
|---|
| 1952 | * is rclViewReal minus scrollbars, if any).
|
|---|
| 1953 | *
|
|---|
| 1954 | * -- rclViewText: the text subrectangle (which
|
|---|
| 1955 | * is rclViewPaint minus borders).
|
|---|
| 1956 | */
|
|---|
| 1957 |
|
|---|
| 1958 | STATIC VOID AdjustViewRects(HWND hwndTextView,
|
|---|
| 1959 | PTEXTVIEWWINDATA ptxvd)
|
|---|
| 1960 | {
|
|---|
| 1961 | ULONG ulScrollCX = WinQuerySysValue(HWND_DESKTOP, SV_CXVSCROLL),
|
|---|
| 1962 | ulScrollCY = WinQuerySysValue(HWND_DESKTOP, SV_CYHSCROLL),
|
|---|
| 1963 | ulOfs;
|
|---|
| 1964 |
|
|---|
| 1965 | // calculate rclViewPaint:
|
|---|
| 1966 | // 1) left
|
|---|
| 1967 | ptxvd->rclViewPaint.xLeft = ptxvd->rclViewReal.xLeft;
|
|---|
| 1968 | // 2) bottom
|
|---|
| 1969 | ptxvd->rclViewPaint.yBottom = ptxvd->rclViewReal.yBottom;
|
|---|
| 1970 | if (ptxvd->fHScrollVisible)
|
|---|
| 1971 | // if we have a horizontal scroll bar at the bottom,
|
|---|
| 1972 | // raise bottom by its height
|
|---|
| 1973 | ptxvd->rclViewPaint.yBottom += ulScrollCY;
|
|---|
| 1974 | // 3) right
|
|---|
| 1975 | ptxvd->rclViewPaint.xRight = ptxvd->rclViewReal.xRight;
|
|---|
| 1976 | if (ptxvd->fVScrollVisible)
|
|---|
| 1977 | // if we have a vertical scroll bar at the right,
|
|---|
| 1978 | // subtract its width from the right
|
|---|
| 1979 | ptxvd->rclViewPaint.xRight -= ulScrollCX;
|
|---|
| 1980 | ptxvd->rclViewPaint.yTop = ptxvd->rclViewReal.yTop;
|
|---|
| 1981 |
|
|---|
| 1982 | // calculate rclViewText from that
|
|---|
| 1983 | ptxvd->rclViewText.xLeft = ptxvd->rclViewPaint.xLeft + ptxvd->cdata.ulXBorder;
|
|---|
| 1984 | ptxvd->rclViewText.yBottom = ptxvd->rclViewPaint.yBottom + ptxvd->cdata.ulYBorder;
|
|---|
| 1985 | ptxvd->rclViewText.xRight = ptxvd->rclViewPaint.xRight - ptxvd->cdata.ulXBorder;
|
|---|
| 1986 | ptxvd->rclViewText.yTop = ptxvd->rclViewPaint.yTop - ptxvd->cdata.ulXBorder;
|
|---|
| 1987 |
|
|---|
| 1988 | // now reposition scroll bars; their sizes may change
|
|---|
| 1989 | // if either the vertical or horizontal scroll bar has
|
|---|
| 1990 | // popped up or been hidden
|
|---|
| 1991 | if (ptxvd->flStyle & XS_VSCROLL)
|
|---|
| 1992 | {
|
|---|
| 1993 | // vertical scroll bar enabled:
|
|---|
| 1994 | ulOfs = 0;
|
|---|
| 1995 | if (ptxvd->fHScrollVisible)
|
|---|
| 1996 | ulOfs = ulScrollCX;
|
|---|
| 1997 | WinSetWindowPos(ptxvd->scrw.hwndVScroll,
|
|---|
| 1998 | HWND_TOP,
|
|---|
| 1999 | ptxvd->rclViewReal.xRight - ulScrollCX,
|
|---|
| 2000 | ulOfs, // y
|
|---|
| 2001 | ulScrollCX, // cx
|
|---|
| 2002 | ptxvd->rclViewReal.yTop - ulOfs, // cy
|
|---|
| 2003 | SWP_MOVE | SWP_SIZE);
|
|---|
| 2004 | }
|
|---|
| 2005 |
|
|---|
| 2006 | if (ptxvd->flStyle & XS_HSCROLL)
|
|---|
| 2007 | {
|
|---|
| 2008 | ulOfs = 0;
|
|---|
| 2009 | if (ptxvd->fVScrollVisible)
|
|---|
| 2010 | ulOfs = ulScrollCX;
|
|---|
| 2011 | WinSetWindowPos(ptxvd->scrw.hwndHScroll,
|
|---|
| 2012 | HWND_TOP,
|
|---|
| 2013 | 0,
|
|---|
| 2014 | 0,
|
|---|
| 2015 | ptxvd->rclViewReal.xRight - ulOfs, // cx
|
|---|
| 2016 | ulScrollCY, // cy
|
|---|
| 2017 | SWP_MOVE | SWP_SIZE);
|
|---|
| 2018 | }
|
|---|
| 2019 | }
|
|---|
| 2020 |
|
|---|
| 2021 | /*
|
|---|
| 2022 | *@@ FormatText2Screen:
|
|---|
| 2023 | * device-dependent version of text formatting
|
|---|
| 2024 | * for the text view window. This calls txvFormatText
|
|---|
| 2025 | * in turn and updates the view's scroll bars.
|
|---|
| 2026 | *
|
|---|
| 2027 | *@@changed V0.9.3 (2000-05-05) [umoeller]: fixed buggy vertical scroll bars
|
|---|
| 2028 | */
|
|---|
| 2029 |
|
|---|
| 2030 | STATIC VOID FormatText2Screen(HWND hwndTextView,
|
|---|
| 2031 | PTEXTVIEWWINDATA ptxvd,
|
|---|
| 2032 | BOOL fAlreadyRecursing, // in: set this to FALSE when calling
|
|---|
| 2033 | BOOL fFullRecalc)
|
|---|
| 2034 | {
|
|---|
| 2035 | ULONG ulWinCX,
|
|---|
| 2036 | ulWinCY;
|
|---|
| 2037 |
|
|---|
| 2038 | // call device-independent formatter with the
|
|---|
| 2039 | // window presentation space
|
|---|
| 2040 | txvFormatText(ptxvd->hps,
|
|---|
| 2041 | &ptxvd->xfd,
|
|---|
| 2042 | &ptxvd->rclViewText,
|
|---|
| 2043 | fFullRecalc);
|
|---|
| 2044 |
|
|---|
| 2045 | ulWinCY = (ptxvd->rclViewText.yTop - ptxvd->rclViewText.yBottom);
|
|---|
| 2046 |
|
|---|
| 2047 | if (ptxvd->scrw.ptlScrollOfs.y < 0)
|
|---|
| 2048 | ptxvd->scrw.ptlScrollOfs.y = 0;
|
|---|
| 2049 | if (ptxvd->scrw.ptlScrollOfs.y > ((LONG)ptxvd->xfd.szlWorkspace.cy - ulWinCY))
|
|---|
| 2050 | ptxvd->scrw.ptlScrollOfs.y = (LONG)ptxvd->xfd.szlWorkspace.cy - ulWinCY;
|
|---|
| 2051 |
|
|---|
| 2052 | // vertical scroll bar enabled at all?
|
|---|
| 2053 | if (ptxvd->flStyle & XS_VSCROLL)
|
|---|
| 2054 | {
|
|---|
| 2055 | BOOL fEnabled = winhUpdateScrollBar(ptxvd->scrw.hwndVScroll,
|
|---|
| 2056 | ulWinCY,
|
|---|
| 2057 | ptxvd->xfd.szlWorkspace.cy,
|
|---|
| 2058 | ptxvd->scrw.ptlScrollOfs.y,
|
|---|
| 2059 | (ptxvd->flStyle & XS_AUTOVHIDE));
|
|---|
| 2060 | // is auto-hide on?
|
|---|
| 2061 | if (ptxvd->flStyle & XS_AUTOVHIDE)
|
|---|
| 2062 | {
|
|---|
| 2063 | // yes, auto-hide on: did visibility change?
|
|---|
| 2064 | if (fEnabled != ptxvd->fVScrollVisible)
|
|---|
| 2065 | // visibility changed:
|
|---|
| 2066 | // if we're not already recursing,
|
|---|
| 2067 | // force calling ourselves again
|
|---|
| 2068 | if (!fAlreadyRecursing)
|
|---|
| 2069 | {
|
|---|
| 2070 | ptxvd->fVScrollVisible = fEnabled;
|
|---|
| 2071 | AdjustViewRects(hwndTextView,
|
|---|
| 2072 | ptxvd);
|
|---|
| 2073 | FormatText2Screen(hwndTextView,
|
|---|
| 2074 | ptxvd,
|
|---|
| 2075 | TRUE, // fAlreadyRecursing
|
|---|
| 2076 | FALSE); // quick format
|
|---|
| 2077 | }
|
|---|
| 2078 | }
|
|---|
| 2079 | }
|
|---|
| 2080 |
|
|---|
| 2081 | ulWinCX = (ptxvd->rclViewText.xRight - ptxvd->rclViewText.xLeft);
|
|---|
| 2082 |
|
|---|
| 2083 | // horizontal scroll bar enabled at all?
|
|---|
| 2084 | if (ptxvd->flStyle & XS_HSCROLL)
|
|---|
| 2085 | {
|
|---|
| 2086 | BOOL fEnabled = winhUpdateScrollBar(ptxvd->scrw.hwndHScroll,
|
|---|
| 2087 | ulWinCX,
|
|---|
| 2088 | ptxvd->xfd.szlWorkspace.cx,
|
|---|
| 2089 | ptxvd->scrw.ptlScrollOfs.x,
|
|---|
| 2090 | (ptxvd->flStyle & XS_AUTOHHIDE));
|
|---|
| 2091 | // is auto-hide on?
|
|---|
| 2092 | if (ptxvd->flStyle & XS_AUTOHHIDE)
|
|---|
| 2093 | {
|
|---|
| 2094 | // yes, auto-hide on: did visibility change?
|
|---|
| 2095 | if (fEnabled != ptxvd->fHScrollVisible)
|
|---|
| 2096 | // visibility changed:
|
|---|
| 2097 | // if we're not already recursing,
|
|---|
| 2098 | // force calling ourselves again (at the bottom)
|
|---|
| 2099 | if (!fAlreadyRecursing)
|
|---|
| 2100 | {
|
|---|
| 2101 | ptxvd->fHScrollVisible = fEnabled;
|
|---|
| 2102 | AdjustViewRects(hwndTextView,
|
|---|
| 2103 | ptxvd);
|
|---|
| 2104 | }
|
|---|
| 2105 | }
|
|---|
| 2106 | }
|
|---|
| 2107 |
|
|---|
| 2108 | WinInvalidateRect(hwndTextView, NULL, FALSE);
|
|---|
| 2109 | }
|
|---|
| 2110 |
|
|---|
| 2111 | /*
|
|---|
| 2112 | *@@ SetWindowText:
|
|---|
| 2113 | * implementation for WM_SETWINDOWPARAMS and
|
|---|
| 2114 | * also WM_CREATE to set the window text.
|
|---|
| 2115 | *
|
|---|
| 2116 | *@@added V0.9.20 (2002-08-10) [umoeller]
|
|---|
| 2117 | */
|
|---|
| 2118 |
|
|---|
| 2119 | VOID SetWindowText(HWND hwndTextView,
|
|---|
| 2120 | PTEXTVIEWWINDATA ptxvd,
|
|---|
| 2121 | PCSZ pcszText)
|
|---|
| 2122 | {
|
|---|
| 2123 | if (pcszText && *pcszText)
|
|---|
| 2124 | {
|
|---|
| 2125 | PXSTRING pstr = &ptxvd->xfd.strViewText;
|
|---|
| 2126 | PSZ p;
|
|---|
| 2127 |
|
|---|
| 2128 | switch (ptxvd->flStyle & XS_FORMAT_MASK)
|
|---|
| 2129 | {
|
|---|
| 2130 | case XS_PLAINTEXT: // 0x0100
|
|---|
| 2131 | xstrcpy(pstr,
|
|---|
| 2132 | pcszText,
|
|---|
| 2133 | 0);
|
|---|
| 2134 | xstrConvertLineFormat(pstr,
|
|---|
| 2135 | CRLF2LF);
|
|---|
| 2136 | p = pstr->psz;
|
|---|
| 2137 | while (p = strchr(p, '\xFF'))
|
|---|
| 2138 | *p = ' ';
|
|---|
| 2139 | break;
|
|---|
| 2140 |
|
|---|
| 2141 | case XS_HTML: // 0x0200
|
|---|
| 2142 | if (p = strdup(pcszText))
|
|---|
| 2143 | {
|
|---|
| 2144 | PSZ p2 = p;
|
|---|
| 2145 | while (p2 = strchr(p2, '\xFF'))
|
|---|
| 2146 | *p2 = ' ';
|
|---|
| 2147 | txvConvertFromHTML(&p, NULL, NULL, NULL);
|
|---|
| 2148 | xstrset(pstr, p);
|
|---|
| 2149 | xstrConvertLineFormat(pstr,
|
|---|
| 2150 | CRLF2LF);
|
|---|
| 2151 | }
|
|---|
| 2152 | break;
|
|---|
| 2153 |
|
|---|
| 2154 | default: // case XS_PREFORMATTED: // 0x0000
|
|---|
| 2155 | // no conversion (default)
|
|---|
| 2156 | xstrcpy(pstr,
|
|---|
| 2157 | pcszText,
|
|---|
| 2158 | 0);
|
|---|
| 2159 | break;
|
|---|
| 2160 | }
|
|---|
| 2161 |
|
|---|
| 2162 | // if the last character of the window text is not "\n",
|
|---|
| 2163 | // add it explicitly here, or our lines processing
|
|---|
| 2164 | // is being funny
|
|---|
| 2165 | // V0.9.20 (2002-08-10) [umoeller]
|
|---|
| 2166 | if (pstr->psz[pstr->ulLength - 1] != '\n')
|
|---|
| 2167 | xstrcatc(pstr, '\n');
|
|---|
| 2168 |
|
|---|
| 2169 | ptxvd->scrw.ptlScrollOfs.x = 0;
|
|---|
| 2170 | ptxvd->scrw.ptlScrollOfs.y = 0;
|
|---|
| 2171 | AdjustViewRects(hwndTextView,
|
|---|
| 2172 | ptxvd);
|
|---|
| 2173 | FormatText2Screen(hwndTextView,
|
|---|
| 2174 | ptxvd,
|
|---|
| 2175 | FALSE,
|
|---|
| 2176 | TRUE); // full format
|
|---|
| 2177 | }
|
|---|
| 2178 | }
|
|---|
| 2179 |
|
|---|
| 2180 | /*
|
|---|
| 2181 | *@@ PaintViewText2Screen:
|
|---|
| 2182 | * device-dependent version of text painting
|
|---|
| 2183 | * for the text view window. This calls txvPaintText
|
|---|
| 2184 | * in turn and updates the view's scroll bars.
|
|---|
| 2185 | */
|
|---|
| 2186 |
|
|---|
| 2187 | STATIC VOID PaintViewText2Screen(PTEXTVIEWWINDATA ptxvd,
|
|---|
| 2188 | PRECTL prcl2Paint) // in: invalid rectangle, can be NULL == paint all
|
|---|
| 2189 | {
|
|---|
| 2190 | ULONG ulLineIndex = 0;
|
|---|
| 2191 | LONG lYOfs = ptxvd->scrw.ptlScrollOfs.y;
|
|---|
| 2192 | txvPaintText(ptxvd->hab,
|
|---|
| 2193 | ptxvd->hps, // paint PS: screen
|
|---|
| 2194 | &ptxvd->xfd, // formatting data
|
|---|
| 2195 | prcl2Paint, // update rectangle given to us
|
|---|
| 2196 | ptxvd->scrw.ptlScrollOfs.x, // current X scrolling offset
|
|---|
| 2197 | &lYOfs, // current Y scrolling offset
|
|---|
| 2198 | TRUE, // draw even partly visible lines
|
|---|
| 2199 | &ulLineIndex);
|
|---|
| 2200 | }
|
|---|
| 2201 |
|
|---|
| 2202 | /*
|
|---|
| 2203 | *@@ PaintViewFocus:
|
|---|
| 2204 | * paint a focus rectangle.
|
|---|
| 2205 | */
|
|---|
| 2206 |
|
|---|
| 2207 | STATIC VOID PaintViewFocus(HPS hps,
|
|---|
| 2208 | PTEXTVIEWWINDATA ptxvd,
|
|---|
| 2209 | BOOL fFocus)
|
|---|
| 2210 | {
|
|---|
| 2211 | POINTL ptl;
|
|---|
| 2212 | HRGN hrgn;
|
|---|
| 2213 | GpiSetClipRegion(hps,
|
|---|
| 2214 | NULLHANDLE,
|
|---|
| 2215 | &hrgn);
|
|---|
| 2216 | GpiSetColor(hps,
|
|---|
| 2217 | (fFocus)
|
|---|
| 2218 | ? WinQuerySysColor(HWND_DESKTOP, SYSCLR_HILITEBACKGROUND, 0)
|
|---|
| 2219 | : ptxvd->lBackColor);
|
|---|
| 2220 | GpiSetLineType(hps, LINETYPE_DOT);
|
|---|
| 2221 | ptl.x = ptxvd->rclViewPaint.xLeft;
|
|---|
| 2222 | ptl.y = ptxvd->rclViewPaint.yBottom;
|
|---|
| 2223 | GpiMove(hps, &ptl);
|
|---|
| 2224 | ptl.x = ptxvd->rclViewPaint.xRight - 1;
|
|---|
| 2225 | ptl.y = ptxvd->rclViewPaint.yTop - 1;
|
|---|
| 2226 | GpiBox(hps,
|
|---|
| 2227 | DRO_OUTLINE,
|
|---|
| 2228 | &ptl,
|
|---|
| 2229 | 0, 0);
|
|---|
| 2230 | }
|
|---|
| 2231 |
|
|---|
| 2232 | /*
|
|---|
| 2233 | *@@ RepaintWord:
|
|---|
| 2234 | *
|
|---|
| 2235 | *@@added V0.9.3 (2000-05-18) [umoeller]
|
|---|
| 2236 | */
|
|---|
| 2237 |
|
|---|
| 2238 | STATIC VOID RepaintWord(PTEXTVIEWWINDATA ptxvd,
|
|---|
| 2239 | PTXVWORD pWordThis,
|
|---|
| 2240 | LONG lColor)
|
|---|
| 2241 | {
|
|---|
| 2242 | POINTL ptlStart;
|
|---|
| 2243 | ULONG flChar = pWordThis->flChar;
|
|---|
| 2244 | PTXVRECTANGLE pLineRcl = pWordThis->pRectangle;
|
|---|
| 2245 |
|
|---|
| 2246 | RECTL rclLine;
|
|---|
| 2247 | rclLine.xLeft = pLineRcl->rcl.xLeft - ptxvd->scrw.ptlScrollOfs.x;
|
|---|
| 2248 | rclLine.xRight = pLineRcl->rcl.xRight - ptxvd->scrw.ptlScrollOfs.x;
|
|---|
| 2249 | rclLine.yBottom = pLineRcl->rcl.yBottom + ptxvd->scrw.ptlScrollOfs.y;
|
|---|
| 2250 | rclLine.yTop = pLineRcl->rcl.yTop + ptxvd->scrw.ptlScrollOfs.y;
|
|---|
| 2251 |
|
|---|
| 2252 | if (pWordThis->pcszLinkTarget)
|
|---|
| 2253 | flChar |= CHS_UNDERSCORE;
|
|---|
| 2254 |
|
|---|
| 2255 | // x start: this word's X coordinate
|
|---|
| 2256 | ptlStart.x = pWordThis->lX - ptxvd->scrw.ptlScrollOfs.x;
|
|---|
| 2257 | // y start: bottom line of rectangle plus highest
|
|---|
| 2258 | // base line offset found in all words (format step 2)
|
|---|
| 2259 | ptlStart.y = rclLine.yBottom + pLineRcl->ulMaxBaseLineOfs;
|
|---|
| 2260 | // pWordThis->ulBaseLineOfs;
|
|---|
| 2261 |
|
|---|
| 2262 | GpiSetCharSet(ptxvd->hps, pWordThis->lcid);
|
|---|
| 2263 | if (pWordThis->lPointSize)
|
|---|
| 2264 | // is outline font:
|
|---|
| 2265 | gpihSetPointSize(ptxvd->hps, pWordThis->lPointSize);
|
|---|
| 2266 |
|
|---|
| 2267 | GpiSetColor(ptxvd->hps,
|
|---|
| 2268 | lColor);
|
|---|
| 2269 |
|
|---|
| 2270 | if (!pWordThis->cEscapeCode)
|
|---|
| 2271 | {
|
|---|
| 2272 | gpihCharStringPosAt(ptxvd->hps,
|
|---|
| 2273 | &ptlStart,
|
|---|
| 2274 | &rclLine,
|
|---|
| 2275 | flChar,
|
|---|
| 2276 | pWordThis->cChars,
|
|---|
| 2277 | (PSZ)pWordThis->pStart);
|
|---|
| 2278 | }
|
|---|
| 2279 | else
|
|---|
| 2280 | // escape to be painted:
|
|---|
| 2281 | DrawListMarker(ptxvd->hps,
|
|---|
| 2282 | &rclLine,
|
|---|
| 2283 | pWordThis,
|
|---|
| 2284 | ptxvd->scrw.ptlScrollOfs.x);
|
|---|
| 2285 | }
|
|---|
| 2286 |
|
|---|
| 2287 | /*
|
|---|
| 2288 | *@@ RepaintAnchor:
|
|---|
| 2289 | *
|
|---|
| 2290 | *@@added V0.9.3 (2000-05-18) [umoeller]
|
|---|
| 2291 | */
|
|---|
| 2292 |
|
|---|
| 2293 | STATIC VOID RepaintAnchor(PTEXTVIEWWINDATA ptxvd,
|
|---|
| 2294 | LONG lColor)
|
|---|
| 2295 | {
|
|---|
| 2296 | PLISTNODE pNode = ptxvd->pWordNodeFirstInAnchor;
|
|---|
| 2297 | PCSZ pcszLinkTarget = NULL;
|
|---|
| 2298 | while (pNode)
|
|---|
| 2299 | {
|
|---|
| 2300 | PTXVWORD pWordThis = (PTXVWORD)pNode->pItemData;
|
|---|
| 2301 | if (!pcszLinkTarget)
|
|---|
| 2302 | // first loop:
|
|---|
| 2303 | pcszLinkTarget = pWordThis->pcszLinkTarget;
|
|---|
| 2304 | else
|
|---|
| 2305 | if (pWordThis->pcszLinkTarget != pcszLinkTarget)
|
|---|
| 2306 | // first word with different anchor:
|
|---|
| 2307 | break;
|
|---|
| 2308 |
|
|---|
| 2309 | RepaintWord(ptxvd,
|
|---|
| 2310 | pWordThis,
|
|---|
| 2311 | lColor);
|
|---|
| 2312 | pNode = pNode->pNext;
|
|---|
| 2313 | }
|
|---|
| 2314 | }
|
|---|
| 2315 |
|
|---|
| 2316 | /*
|
|---|
| 2317 | *@@ ProcessCreate:
|
|---|
| 2318 | * implementation for WM_CREATE in fnwpTextView.
|
|---|
| 2319 | *
|
|---|
| 2320 | *@@added V1.0.0 (2002-08-12) [umoeller]
|
|---|
| 2321 | */
|
|---|
| 2322 |
|
|---|
| 2323 | STATIC MRESULT ProcessCreate(HWND hwndTextView, MPARAM mp1, MPARAM mp2)
|
|---|
| 2324 | {
|
|---|
| 2325 | PXTEXTVIEWCDATA pcd = (PXTEXTVIEWCDATA)mp1;
|
|---|
| 2326 | // can be NULL
|
|---|
| 2327 | PCREATESTRUCT pcs = (PCREATESTRUCT)mp2;
|
|---|
| 2328 |
|
|---|
| 2329 | MRESULT mrc = (MRESULT)TRUE; // error
|
|---|
| 2330 | PTEXTVIEWWINDATA ptxvd;
|
|---|
| 2331 |
|
|---|
| 2332 | // allocate TEXTVIEWWINDATA for QWL_PRIVATE
|
|---|
| 2333 | if (ptxvd = (PTEXTVIEWWINDATA)malloc(sizeof(TEXTVIEWWINDATA)))
|
|---|
| 2334 | {
|
|---|
| 2335 | SIZEL szlPage = {0, 0};
|
|---|
| 2336 | BOOL fShow = FALSE;
|
|---|
| 2337 |
|
|---|
| 2338 | // query message queue
|
|---|
| 2339 | HMQ hmq = WinQueryWindowULong(hwndTextView, QWL_HMQ);
|
|---|
| 2340 | // get codepage of message queue
|
|---|
| 2341 | ULONG ulCodepage = WinQueryCp(hmq);
|
|---|
| 2342 |
|
|---|
| 2343 | memset(ptxvd, 0, sizeof(TEXTVIEWWINDATA));
|
|---|
| 2344 | WinSetWindowPtr(hwndTextView, QWL_PRIVATE, ptxvd);
|
|---|
| 2345 |
|
|---|
| 2346 | ptxvd->hab = WinQueryAnchorBlock(hwndTextView);
|
|---|
| 2347 |
|
|---|
| 2348 | ptxvd->hdc = WinOpenWindowDC(hwndTextView);
|
|---|
| 2349 | ptxvd->hps = GpiCreatePS(ptxvd->hab,
|
|---|
| 2350 | ptxvd->hdc,
|
|---|
| 2351 | &szlPage, // use same page size as device
|
|---|
| 2352 | PU_PELS | GPIT_MICRO | GPIA_ASSOC);
|
|---|
| 2353 |
|
|---|
| 2354 | // copy window style flags V0.9.20 (2002-08-10) [umoeller]
|
|---|
| 2355 | ptxvd->flStyle = pcs->flStyle;
|
|---|
| 2356 |
|
|---|
| 2357 | gpihSwitchToRGB(ptxvd->hps);
|
|---|
| 2358 |
|
|---|
| 2359 | // set codepage; GPI defaults this to
|
|---|
| 2360 | // the process codepage
|
|---|
| 2361 | GpiSetCp(ptxvd->hps, ulCodepage);
|
|---|
| 2362 |
|
|---|
| 2363 | txvInitFormat(&ptxvd->xfd);
|
|---|
| 2364 |
|
|---|
| 2365 | // copy control data, if present
|
|---|
| 2366 | if (pcd)
|
|---|
| 2367 | memcpy(&ptxvd->cdata, pcd, pcd->cbData);
|
|---|
| 2368 |
|
|---|
| 2369 | // check values which might cause null divisions
|
|---|
| 2370 | if (ptxvd->cdata.ulVScrollLineUnit == 0)
|
|---|
| 2371 | ptxvd->cdata.ulVScrollLineUnit = 15;
|
|---|
| 2372 | if (ptxvd->cdata.ulHScrollLineUnit == 0)
|
|---|
| 2373 | ptxvd->cdata.ulHScrollLineUnit = 15;
|
|---|
| 2374 |
|
|---|
| 2375 | ptxvd->fAcceptsPresParamsNow = FALSE;
|
|---|
| 2376 |
|
|---|
| 2377 | // copy window dimensions from CREATESTRUCT
|
|---|
| 2378 | ptxvd->rclViewReal.xLeft = 0;
|
|---|
| 2379 | ptxvd->rclViewReal.yBottom = 0;
|
|---|
| 2380 | ptxvd->rclViewReal.xRight = pcs->cx;
|
|---|
| 2381 | ptxvd->rclViewReal.yTop = pcs->cy;
|
|---|
| 2382 |
|
|---|
| 2383 | winhCreateScroller(hwndTextView,
|
|---|
| 2384 | &ptxvd->scrw,
|
|---|
| 2385 | ID_VSCROLL,
|
|---|
| 2386 | ID_HSCROLL);
|
|---|
| 2387 |
|
|---|
| 2388 | fShow = ((ptxvd->flStyle & XS_VSCROLL) != 0);
|
|---|
| 2389 | WinShowWindow(ptxvd->scrw.hwndVScroll, fShow);
|
|---|
| 2390 | ptxvd->fVScrollVisible = fShow;
|
|---|
| 2391 |
|
|---|
| 2392 | fShow = ((ptxvd->flStyle & XS_HSCROLL) != 0);
|
|---|
| 2393 | WinShowWindow(ptxvd->scrw.hwndHScroll, fShow);
|
|---|
| 2394 | ptxvd->fHScrollVisible = fShow;
|
|---|
| 2395 |
|
|---|
| 2396 | if (ptxvd->flStyle & XS_WORDWRAP)
|
|---|
| 2397 | // word-wrapping should be enabled from the start:
|
|---|
| 2398 | // V0.9.20 (2002-08-10) [umoeller]
|
|---|
| 2399 | ptxvd->xfd.fmtpStandard.fWordWrap = TRUE;
|
|---|
| 2400 |
|
|---|
| 2401 | // set "code" format
|
|---|
| 2402 | SetFormatFont(ptxvd->hps,
|
|---|
| 2403 | &ptxvd->xfd.fmtcCode,
|
|---|
| 2404 | 6,
|
|---|
| 2405 | "System VIO");
|
|---|
| 2406 |
|
|---|
| 2407 | // get colors from presparams/syscolors
|
|---|
| 2408 | UpdateTextViewPresData(hwndTextView, ptxvd);
|
|---|
| 2409 |
|
|---|
| 2410 | AdjustViewRects(hwndTextView,
|
|---|
| 2411 | ptxvd);
|
|---|
| 2412 |
|
|---|
| 2413 | if (ptxvd->flStyle & XS_HTML)
|
|---|
| 2414 | {
|
|---|
| 2415 | // if we're operating in HTML mode, set a
|
|---|
| 2416 | // different default paragraph format to
|
|---|
| 2417 | // make things prettier
|
|---|
| 2418 | // V0.9.20 (2002-08-10) [umoeller]
|
|---|
| 2419 | ptxvd->xfd.fmtpStandard.lSpaceBefore = 5;
|
|---|
| 2420 | ptxvd->xfd.fmtpStandard.lSpaceAfter = 5;
|
|---|
| 2421 | }
|
|---|
| 2422 |
|
|---|
| 2423 | // setting the window text on window creation never
|
|---|
| 2424 | // worked V0.9.20 (2002-08-10) [umoeller]
|
|---|
| 2425 | if (pcs->pszText)
|
|---|
| 2426 | SetWindowText(hwndTextView,
|
|---|
| 2427 | ptxvd,
|
|---|
| 2428 | pcs->pszText);
|
|---|
| 2429 |
|
|---|
| 2430 | mrc = (MRESULT)FALSE; // OK
|
|---|
| 2431 | }
|
|---|
| 2432 |
|
|---|
| 2433 | return mrc;
|
|---|
| 2434 | }
|
|---|
| 2435 |
|
|---|
| 2436 | /*
|
|---|
| 2437 | *@@ ProcessPaint:
|
|---|
| 2438 | * implementation for WM_PAINT in fnwpTextView.
|
|---|
| 2439 | *
|
|---|
| 2440 | *@@added V1.0.0 (2002-08-12) [umoeller]
|
|---|
| 2441 | */
|
|---|
| 2442 |
|
|---|
| 2443 | STATIC VOID ProcessPaint(HWND hwndTextView)
|
|---|
| 2444 | {
|
|---|
| 2445 | PTEXTVIEWWINDATA ptxvd;
|
|---|
| 2446 | if (ptxvd = (PTEXTVIEWWINDATA)WinQueryWindowPtr(hwndTextView, QWL_PRIVATE))
|
|---|
| 2447 | {
|
|---|
| 2448 | HRGN hrgnOldClip;
|
|---|
| 2449 | RECTL rclClip;
|
|---|
| 2450 | RECTL rcl2Update;
|
|---|
| 2451 |
|
|---|
| 2452 | // get update rectangle
|
|---|
| 2453 | WinQueryUpdateRect(hwndTextView,
|
|---|
| 2454 | &rcl2Update);
|
|---|
| 2455 | // since we're not using WinBeginPaint,
|
|---|
| 2456 | // we must validate the update region,
|
|---|
| 2457 | // or we'll get bombed with WM_PAINT msgs
|
|---|
| 2458 | WinValidateRect(hwndTextView,
|
|---|
| 2459 | NULL,
|
|---|
| 2460 | FALSE);
|
|---|
| 2461 |
|
|---|
| 2462 | // reset clip region to "all"
|
|---|
| 2463 | GpiSetClipRegion(ptxvd->hps,
|
|---|
| 2464 | NULLHANDLE,
|
|---|
| 2465 | &hrgnOldClip); // out: old clip region
|
|---|
| 2466 | // reduce clip region to update rectangle
|
|---|
| 2467 | GpiIntersectClipRectangle(ptxvd->hps,
|
|---|
| 2468 | &rcl2Update); // exclusive
|
|---|
| 2469 |
|
|---|
| 2470 | // draw little box at the bottom right
|
|---|
| 2471 | // (in between scroll bars) if we have
|
|---|
| 2472 | // both vertical and horizontal scroll bars
|
|---|
| 2473 | if ( (ptxvd->flStyle & (XS_VSCROLL | XS_HSCROLL))
|
|---|
| 2474 | == (XS_VSCROLL | XS_HSCROLL)
|
|---|
| 2475 | && (ptxvd->fVScrollVisible)
|
|---|
| 2476 | && (ptxvd->fHScrollVisible)
|
|---|
| 2477 | )
|
|---|
| 2478 | {
|
|---|
| 2479 | RECTL rclBox;
|
|---|
| 2480 | rclBox.xLeft = ptxvd->rclViewPaint.xRight;
|
|---|
| 2481 | rclBox.yBottom = 0;
|
|---|
| 2482 | rclBox.xRight = rclBox.xLeft + WinQuerySysValue(HWND_DESKTOP, SV_CXVSCROLL);
|
|---|
| 2483 | rclBox.yTop = WinQuerySysValue(HWND_DESKTOP, SV_CYHSCROLL);
|
|---|
| 2484 | WinFillRect(ptxvd->hps,
|
|---|
| 2485 | &rclBox,
|
|---|
| 2486 | WinQuerySysColor(HWND_DESKTOP,
|
|---|
| 2487 | SYSCLR_DIALOGBACKGROUND,
|
|---|
| 2488 | 0));
|
|---|
| 2489 | }
|
|---|
| 2490 |
|
|---|
| 2491 | // paint "view paint" rectangle white;
|
|---|
| 2492 | // this can be larger than "view text"
|
|---|
| 2493 | WinFillRect(ptxvd->hps,
|
|---|
| 2494 | &ptxvd->rclViewPaint, // exclusive
|
|---|
| 2495 | ptxvd->lBackColor);
|
|---|
| 2496 |
|
|---|
| 2497 | // now reduce clipping rectangle to "view text" rectangle
|
|---|
| 2498 | rclClip.xLeft = ptxvd->rclViewText.xLeft;
|
|---|
| 2499 | rclClip.xRight = ptxvd->rclViewText.xRight - 1;
|
|---|
| 2500 | rclClip.yBottom = ptxvd->rclViewText.yBottom;
|
|---|
| 2501 | rclClip.yTop = ptxvd->rclViewText.yTop - 1;
|
|---|
| 2502 | GpiIntersectClipRectangle(ptxvd->hps,
|
|---|
| 2503 | &rclClip); // exclusive
|
|---|
| 2504 | // finally, draw text lines in invalid rectangle;
|
|---|
| 2505 | // this subfunction is smart enough to redraw only
|
|---|
| 2506 | // the lines which intersect with rcl2Update
|
|---|
| 2507 | GpiSetColor(ptxvd->hps, ptxvd->lForeColor);
|
|---|
| 2508 | PaintViewText2Screen(ptxvd,
|
|---|
| 2509 | &rcl2Update);
|
|---|
| 2510 |
|
|---|
| 2511 | if ( (!(ptxvd->flStyle & XS_STATIC))
|
|---|
| 2512 | // V0.9.20 (2002-08-10) [umoeller]
|
|---|
| 2513 | && (WinQueryFocus(HWND_DESKTOP) == hwndTextView)
|
|---|
| 2514 | )
|
|---|
| 2515 | {
|
|---|
| 2516 | // we have the focus:
|
|---|
| 2517 | // reset clip region to "all"
|
|---|
| 2518 | GpiSetClipRegion(ptxvd->hps,
|
|---|
| 2519 | NULLHANDLE,
|
|---|
| 2520 | &hrgnOldClip); // out: old clip region
|
|---|
| 2521 | PaintViewFocus(ptxvd->hps,
|
|---|
| 2522 | ptxvd,
|
|---|
| 2523 | TRUE);
|
|---|
| 2524 | }
|
|---|
| 2525 |
|
|---|
| 2526 | ptxvd->fAcceptsPresParamsNow = TRUE;
|
|---|
| 2527 | }
|
|---|
| 2528 | }
|
|---|
| 2529 |
|
|---|
| 2530 | /*
|
|---|
| 2531 | *@@ ProcessPresParamChanged:
|
|---|
| 2532 | * implementation for WM_PRESPARAMCHANGED in fnwpTextView.
|
|---|
| 2533 | *
|
|---|
| 2534 | *@@added V1.0.0 (2002-08-12) [umoeller]
|
|---|
| 2535 | */
|
|---|
| 2536 |
|
|---|
| 2537 | STATIC VOID ProcessPresParamChanged(HWND hwndTextView, MPARAM mp1)
|
|---|
| 2538 | {
|
|---|
| 2539 | PTEXTVIEWWINDATA ptxvd;
|
|---|
| 2540 | if (ptxvd = (PTEXTVIEWWINDATA)WinQueryWindowPtr(hwndTextView, QWL_PRIVATE))
|
|---|
| 2541 | {
|
|---|
| 2542 | switch ((LONG)mp1)
|
|---|
| 2543 | {
|
|---|
| 2544 | case 0: // layout palette thing dropped
|
|---|
| 2545 | case PP_BACKGROUNDCOLOR:
|
|---|
| 2546 | case PP_FOREGROUNDCOLOR:
|
|---|
| 2547 | case PP_FONTNAMESIZE:
|
|---|
| 2548 | // re-query our presparams
|
|---|
| 2549 | UpdateTextViewPresData(hwndTextView, ptxvd);
|
|---|
| 2550 | }
|
|---|
| 2551 |
|
|---|
| 2552 | if (ptxvd->fAcceptsPresParamsNow)
|
|---|
| 2553 | FormatText2Screen(hwndTextView,
|
|---|
| 2554 | ptxvd,
|
|---|
| 2555 | FALSE,
|
|---|
| 2556 | TRUE); // full reformat
|
|---|
| 2557 | }
|
|---|
| 2558 | }
|
|---|
| 2559 |
|
|---|
| 2560 | /*
|
|---|
| 2561 | *@@ ProcessScroll:
|
|---|
| 2562 | *
|
|---|
| 2563 | *@@added V1.0.1 (2003-01-25) [umoeller]
|
|---|
| 2564 | */
|
|---|
| 2565 |
|
|---|
| 2566 | STATIC VOID ProcessScroll(HWND hwndTextView,
|
|---|
| 2567 | ULONG msg,
|
|---|
| 2568 | MPARAM mp2)
|
|---|
| 2569 | {
|
|---|
| 2570 | PTEXTVIEWWINDATA ptxvd;
|
|---|
| 2571 | if (ptxvd = (PTEXTVIEWWINDATA)WinQueryWindowPtr(hwndTextView, QWL_PRIVATE))
|
|---|
| 2572 | {
|
|---|
| 2573 | POINTL ptlScroll = {0, 0};
|
|---|
| 2574 | if ( (msg == WM_VSCROLL)
|
|---|
| 2575 | && (ptxvd->fVScrollVisible)
|
|---|
| 2576 | )
|
|---|
| 2577 | {
|
|---|
| 2578 | LONG cy = ptxvd->rclViewText.yTop - ptxvd->rclViewText.yBottom;
|
|---|
| 2579 | ptlScroll.y = winhHandleScrollMsg(ptxvd->scrw.hwndVScroll,
|
|---|
| 2580 | &ptxvd->scrw.ptlScrollOfs.y,
|
|---|
| 2581 | cy,
|
|---|
| 2582 | ptxvd->xfd.szlWorkspace.cy,
|
|---|
| 2583 | ptxvd->cdata.ulVScrollLineUnit,
|
|---|
| 2584 | msg,
|
|---|
| 2585 | mp2);
|
|---|
| 2586 | }
|
|---|
| 2587 | else if (ptxvd->fHScrollVisible)
|
|---|
| 2588 | {
|
|---|
| 2589 | LONG cx = ptxvd->rclViewText.xRight - ptxvd->rclViewText.xLeft;
|
|---|
| 2590 | ptlScroll.x = winhHandleScrollMsg(ptxvd->scrw.hwndHScroll,
|
|---|
| 2591 | &ptxvd->scrw.ptlScrollOfs.x,
|
|---|
| 2592 | cx,
|
|---|
| 2593 | ptxvd->xfd.szlWorkspace.cx,
|
|---|
| 2594 | ptxvd->cdata.ulHScrollLineUnit,
|
|---|
| 2595 | msg,
|
|---|
| 2596 | mp2);
|
|---|
| 2597 | }
|
|---|
| 2598 |
|
|---|
| 2599 | if (ptlScroll.x || ptlScroll.y)
|
|---|
| 2600 | winhScrollWindow(hwndTextView,
|
|---|
| 2601 | &ptxvd->rclViewText,
|
|---|
| 2602 | &ptlScroll);
|
|---|
| 2603 | }
|
|---|
| 2604 | }
|
|---|
| 2605 |
|
|---|
| 2606 | /*
|
|---|
| 2607 | *@@ ProcessSetFocus:
|
|---|
| 2608 | * implementation for WM_SETFOCUS in fnwpTextView.
|
|---|
| 2609 | *
|
|---|
| 2610 | *@@added V1.0.0 (2002-08-12) [umoeller]
|
|---|
| 2611 | */
|
|---|
| 2612 |
|
|---|
| 2613 | STATIC VOID ProcessSetFocus(HWND hwndTextView, MPARAM mp2)
|
|---|
| 2614 | {
|
|---|
| 2615 | PTEXTVIEWWINDATA ptxvd;
|
|---|
| 2616 | if (ptxvd = (PTEXTVIEWWINDATA)WinQueryWindowPtr(hwndTextView, QWL_PRIVATE))
|
|---|
| 2617 | {
|
|---|
| 2618 | if (ptxvd->flStyle & XS_STATIC)
|
|---|
| 2619 | {
|
|---|
| 2620 | if (mp2)
|
|---|
| 2621 | {
|
|---|
| 2622 | // we're receiving the focus, but shouldn't have it:
|
|---|
| 2623 | // then behave like the static control does, that is,
|
|---|
| 2624 | // give focus to the next window in the dialog
|
|---|
| 2625 | HWND hwnd = hwndTextView,
|
|---|
| 2626 | hwndStart = hwnd;
|
|---|
| 2627 |
|
|---|
| 2628 | while (TRUE)
|
|---|
| 2629 | {
|
|---|
| 2630 | ULONG flStyle;
|
|---|
| 2631 |
|
|---|
| 2632 | if (!(hwnd = WinQueryWindow(hwnd, QW_NEXT)))
|
|---|
| 2633 | hwnd = WinQueryWindow(WinQueryWindow(hwndStart, QW_PARENT), QW_TOP);
|
|---|
| 2634 |
|
|---|
| 2635 | // avoid endless looping
|
|---|
| 2636 | if (hwnd == hwndStart)
|
|---|
| 2637 | {
|
|---|
| 2638 | if ( (hwnd = WinQueryWindow(hwnd, QW_OWNER))
|
|---|
| 2639 | && (hwnd == hwndStart)
|
|---|
| 2640 | )
|
|---|
| 2641 | hwnd = NULLHANDLE;
|
|---|
| 2642 |
|
|---|
| 2643 | break;
|
|---|
| 2644 | }
|
|---|
| 2645 |
|
|---|
| 2646 | if ( (flStyle = WinQueryWindowULong(hwnd, QWL_STYLE))
|
|---|
| 2647 | && (flStyle & (WS_DISABLED | WS_TABSTOP | WS_VISIBLE)
|
|---|
| 2648 | == (WS_TABSTOP | WS_VISIBLE))
|
|---|
| 2649 | )
|
|---|
| 2650 | {
|
|---|
| 2651 | WinSetFocus(HWND_DESKTOP, hwnd);
|
|---|
| 2652 | break;
|
|---|
| 2653 | }
|
|---|
| 2654 | };
|
|---|
| 2655 | }
|
|---|
| 2656 | }
|
|---|
| 2657 | else
|
|---|
| 2658 | {
|
|---|
| 2659 | HPS hps = WinGetPS(hwndTextView);
|
|---|
| 2660 | gpihSwitchToRGB(hps);
|
|---|
| 2661 | PaintViewFocus(hps,
|
|---|
| 2662 | ptxvd,
|
|---|
| 2663 | (mp2 != 0));
|
|---|
| 2664 | WinReleasePS(hps);
|
|---|
| 2665 | }
|
|---|
| 2666 | }
|
|---|
| 2667 | }
|
|---|
| 2668 |
|
|---|
| 2669 | /*
|
|---|
| 2670 | *@@ ProcessButton1Down:
|
|---|
| 2671 | * implementation for WM_BUTTON1DOWN in fnwpTextView.
|
|---|
| 2672 | *
|
|---|
| 2673 | *@@added V1.0.0 (2002-08-12) [umoeller]
|
|---|
| 2674 | */
|
|---|
| 2675 |
|
|---|
| 2676 | STATIC MRESULT ProcessButton1Down(HWND hwndTextView, MPARAM mp1)
|
|---|
| 2677 | {
|
|---|
| 2678 | MRESULT mrc = 0;
|
|---|
| 2679 | PTEXTVIEWWINDATA ptxvd;
|
|---|
| 2680 |
|
|---|
| 2681 | if (ptxvd = (PTEXTVIEWWINDATA)WinQueryWindowPtr(hwndTextView, QWL_PRIVATE))
|
|---|
| 2682 | {
|
|---|
| 2683 | POINTL ptlPos;
|
|---|
| 2684 | PLISTNODE pWordNodeClicked;
|
|---|
| 2685 |
|
|---|
| 2686 | ptlPos.x = SHORT1FROMMP(mp1) + ptxvd->scrw.ptlScrollOfs.x;
|
|---|
| 2687 | ptlPos.y = SHORT2FROMMP(mp1) - ptxvd->scrw.ptlScrollOfs.y;
|
|---|
| 2688 |
|
|---|
| 2689 | if ( (!(ptxvd->flStyle & XS_STATIC))
|
|---|
| 2690 | // V0.9.20 (2002-08-10) [umoeller]
|
|---|
| 2691 | && (hwndTextView != WinQueryFocus(HWND_DESKTOP))
|
|---|
| 2692 | )
|
|---|
| 2693 | WinSetFocus(HWND_DESKTOP, hwndTextView);
|
|---|
| 2694 |
|
|---|
| 2695 | ptxvd->pcszLastLinkClicked = NULL;
|
|---|
| 2696 |
|
|---|
| 2697 | if (pWordNodeClicked = txvFindWordFromPoint(&ptxvd->xfd,
|
|---|
| 2698 | &ptlPos))
|
|---|
| 2699 | {
|
|---|
| 2700 | PTXVWORD pWordClicked = (PTXVWORD)pWordNodeClicked->pItemData;
|
|---|
| 2701 |
|
|---|
| 2702 | // store link target (can be NULL)
|
|---|
| 2703 | if (ptxvd->pcszLastLinkClicked = pWordClicked->pcszLinkTarget)
|
|---|
| 2704 | {
|
|---|
| 2705 | // word has a link target:
|
|---|
| 2706 | PLISTNODE pNode = pWordNodeClicked;
|
|---|
| 2707 |
|
|---|
| 2708 | // reset first word of anchor
|
|---|
| 2709 | ptxvd->pWordNodeFirstInAnchor = NULL;
|
|---|
| 2710 |
|
|---|
| 2711 | // go back to find the first word which has this anchor,
|
|---|
| 2712 | // because we need to repaint them all
|
|---|
| 2713 | while (pNode)
|
|---|
| 2714 | {
|
|---|
| 2715 | PTXVWORD pWordThis = (PTXVWORD)pNode->pItemData;
|
|---|
| 2716 | if (pWordThis->pcszLinkTarget == pWordClicked->pcszLinkTarget)
|
|---|
| 2717 | {
|
|---|
| 2718 | // still has same anchor:
|
|---|
| 2719 | // go for previous
|
|---|
| 2720 | ptxvd->pWordNodeFirstInAnchor = pNode;
|
|---|
| 2721 | pNode = pNode->pPrevious;
|
|---|
| 2722 | }
|
|---|
| 2723 | else
|
|---|
| 2724 | // different anchor:
|
|---|
| 2725 | // pNodeFirst points to first node with same anchor now
|
|---|
| 2726 | break;
|
|---|
| 2727 | }
|
|---|
| 2728 |
|
|---|
| 2729 | RepaintAnchor(ptxvd,
|
|---|
| 2730 | RGBCOL_RED);
|
|---|
| 2731 | }
|
|---|
| 2732 | }
|
|---|
| 2733 |
|
|---|
| 2734 | WinSetCapture(HWND_DESKTOP, hwndTextView);
|
|---|
| 2735 | mrc = (MRESULT)TRUE;
|
|---|
| 2736 | }
|
|---|
| 2737 |
|
|---|
| 2738 | return mrc;
|
|---|
| 2739 | }
|
|---|
| 2740 |
|
|---|
| 2741 | /*
|
|---|
| 2742 | *@@ ProcessButton1Up:
|
|---|
| 2743 | * implementation for WM_BUTTON1UP in fnwpTextView.
|
|---|
| 2744 | *
|
|---|
| 2745 | *@@added V1.0.0 (2002-08-12) [umoeller]
|
|---|
| 2746 | */
|
|---|
| 2747 |
|
|---|
| 2748 | STATIC MRESULT ProcessButton1Up(HWND hwndTextView, MPARAM mp1)
|
|---|
| 2749 | {
|
|---|
| 2750 | MRESULT mrc = 0;
|
|---|
| 2751 | PTEXTVIEWWINDATA ptxvd;
|
|---|
| 2752 |
|
|---|
| 2753 | if (ptxvd = (PTEXTVIEWWINDATA)WinQueryWindowPtr(hwndTextView, QWL_PRIVATE))
|
|---|
| 2754 | {
|
|---|
| 2755 | POINTL ptlPos;
|
|---|
| 2756 | HWND hwndOwner = NULLHANDLE;
|
|---|
| 2757 |
|
|---|
| 2758 | ptlPos.x = SHORT1FROMMP(mp1) + ptxvd->scrw.ptlScrollOfs.x;
|
|---|
| 2759 | ptlPos.y = SHORT2FROMMP(mp1) - ptxvd->scrw.ptlScrollOfs.y;
|
|---|
| 2760 | WinSetCapture(HWND_DESKTOP, NULLHANDLE);
|
|---|
| 2761 |
|
|---|
| 2762 | if (ptxvd->pcszLastLinkClicked)
|
|---|
| 2763 | {
|
|---|
| 2764 | RepaintAnchor(ptxvd,
|
|---|
| 2765 | ptxvd->lForeColor);
|
|---|
| 2766 |
|
|---|
| 2767 | // nofify owner
|
|---|
| 2768 | if (hwndOwner = WinQueryWindow(hwndTextView, QW_OWNER))
|
|---|
| 2769 | WinPostMsg(hwndOwner,
|
|---|
| 2770 | WM_CONTROL,
|
|---|
| 2771 | MPFROM2SHORT(WinQueryWindowUShort(hwndTextView,
|
|---|
| 2772 | QWS_ID),
|
|---|
| 2773 | TXVN_LINK),
|
|---|
| 2774 | (MPARAM)(ULONG)(ptxvd->pcszLastLinkClicked));
|
|---|
| 2775 | }
|
|---|
| 2776 |
|
|---|
| 2777 | mrc = (MRESULT)TRUE;
|
|---|
| 2778 | }
|
|---|
| 2779 |
|
|---|
| 2780 | return mrc;
|
|---|
| 2781 | }
|
|---|
| 2782 |
|
|---|
| 2783 | /*
|
|---|
| 2784 | *@@ ProcessChar:
|
|---|
| 2785 | * implementation for WM_CHAR in fnwpTextView.
|
|---|
| 2786 | *
|
|---|
| 2787 | *@@added V1.0.0 (2002-08-12) [umoeller]
|
|---|
| 2788 | */
|
|---|
| 2789 |
|
|---|
| 2790 | STATIC MRESULT ProcessChar(HWND hwndTextView, MPARAM mp1, MPARAM mp2)
|
|---|
| 2791 | {
|
|---|
| 2792 | MRESULT mrc = 0;
|
|---|
| 2793 | PTEXTVIEWWINDATA ptxvd;
|
|---|
| 2794 |
|
|---|
| 2795 | if (ptxvd = (PTEXTVIEWWINDATA)WinQueryWindowPtr(hwndTextView, QWL_PRIVATE))
|
|---|
| 2796 | {
|
|---|
| 2797 | BOOL fDefProc = TRUE;
|
|---|
| 2798 | USHORT usFlags = SHORT1FROMMP(mp1);
|
|---|
| 2799 | // USHORT usch = SHORT1FROMMP(mp2);
|
|---|
| 2800 | USHORT usvk = SHORT2FROMMP(mp2);
|
|---|
| 2801 |
|
|---|
| 2802 | if (usFlags & KC_VIRTUALKEY)
|
|---|
| 2803 | {
|
|---|
| 2804 | ULONG ulMsg = 0;
|
|---|
| 2805 | USHORT usID = ID_VSCROLL;
|
|---|
| 2806 | SHORT sPos = 0;
|
|---|
| 2807 | SHORT usCmd = 0;
|
|---|
| 2808 | fDefProc = FALSE;
|
|---|
| 2809 |
|
|---|
| 2810 | switch (usvk)
|
|---|
| 2811 | {
|
|---|
| 2812 | case VK_UP:
|
|---|
| 2813 | ulMsg = WM_VSCROLL;
|
|---|
| 2814 | usCmd = SB_LINEUP;
|
|---|
| 2815 | break;
|
|---|
| 2816 |
|
|---|
| 2817 | case VK_DOWN:
|
|---|
| 2818 | ulMsg = WM_VSCROLL;
|
|---|
| 2819 | usCmd = SB_LINEDOWN;
|
|---|
| 2820 | break;
|
|---|
| 2821 |
|
|---|
| 2822 | case VK_RIGHT:
|
|---|
| 2823 | ulMsg = WM_HSCROLL;
|
|---|
| 2824 | usCmd = SB_LINERIGHT;
|
|---|
| 2825 | break;
|
|---|
| 2826 |
|
|---|
| 2827 | case VK_LEFT:
|
|---|
| 2828 | ulMsg = WM_HSCROLL;
|
|---|
| 2829 | usCmd = SB_LINELEFT;
|
|---|
| 2830 | break;
|
|---|
| 2831 |
|
|---|
| 2832 | case VK_PAGEUP:
|
|---|
| 2833 | ulMsg = WM_VSCROLL;
|
|---|
| 2834 | if (usFlags & KC_CTRL)
|
|---|
| 2835 | {
|
|---|
| 2836 | sPos = 0;
|
|---|
| 2837 | usCmd = SB_SLIDERPOSITION;
|
|---|
| 2838 | }
|
|---|
| 2839 | else
|
|---|
| 2840 | usCmd = SB_PAGEUP;
|
|---|
| 2841 | break;
|
|---|
| 2842 |
|
|---|
| 2843 | case VK_PAGEDOWN:
|
|---|
| 2844 | ulMsg = WM_VSCROLL;
|
|---|
| 2845 | if (usFlags & KC_CTRL)
|
|---|
| 2846 | {
|
|---|
| 2847 | sPos = ptxvd->xfd.szlWorkspace.cy;
|
|---|
| 2848 | usCmd = SB_SLIDERPOSITION;
|
|---|
| 2849 | }
|
|---|
| 2850 | else
|
|---|
| 2851 | usCmd = SB_PAGEDOWN;
|
|---|
| 2852 | break;
|
|---|
| 2853 |
|
|---|
| 2854 | case VK_HOME:
|
|---|
| 2855 | if (usFlags & KC_CTRL)
|
|---|
| 2856 | // vertical:
|
|---|
| 2857 | ulMsg = WM_VSCROLL;
|
|---|
| 2858 | else
|
|---|
| 2859 | ulMsg = WM_HSCROLL;
|
|---|
| 2860 |
|
|---|
| 2861 | sPos = 0;
|
|---|
| 2862 | usCmd = SB_SLIDERPOSITION;
|
|---|
| 2863 | break;
|
|---|
| 2864 |
|
|---|
| 2865 | case VK_END:
|
|---|
| 2866 | if (usFlags & KC_CTRL)
|
|---|
| 2867 | {
|
|---|
| 2868 | // vertical:
|
|---|
| 2869 | ulMsg = WM_VSCROLL;
|
|---|
| 2870 | sPos = ptxvd->xfd.szlWorkspace.cy;
|
|---|
| 2871 | }
|
|---|
| 2872 | else
|
|---|
| 2873 | {
|
|---|
| 2874 | ulMsg = WM_HSCROLL;
|
|---|
| 2875 | sPos = ptxvd->xfd.szlWorkspace.cx;
|
|---|
| 2876 | }
|
|---|
| 2877 |
|
|---|
| 2878 | usCmd = SB_SLIDERPOSITION;
|
|---|
| 2879 | break;
|
|---|
| 2880 |
|
|---|
| 2881 | default:
|
|---|
| 2882 | // other:
|
|---|
| 2883 | fDefProc = TRUE;
|
|---|
| 2884 | }
|
|---|
| 2885 |
|
|---|
| 2886 | if ( ((usFlags & KC_KEYUP) == 0)
|
|---|
| 2887 | && (ulMsg)
|
|---|
| 2888 | )
|
|---|
| 2889 | WinSendMsg(hwndTextView,
|
|---|
| 2890 | ulMsg,
|
|---|
| 2891 | MPFROMSHORT(usID),
|
|---|
| 2892 | MPFROM2SHORT(sPos,
|
|---|
| 2893 | usCmd));
|
|---|
| 2894 | }
|
|---|
| 2895 |
|
|---|
| 2896 | if (fDefProc)
|
|---|
| 2897 | mrc = WinDefWindowProc(hwndTextView, WM_CHAR, mp1, mp2);
|
|---|
| 2898 | // sends to owner
|
|---|
| 2899 | else
|
|---|
| 2900 | mrc = (MPARAM)TRUE;
|
|---|
| 2901 | }
|
|---|
| 2902 |
|
|---|
| 2903 | return mrc;
|
|---|
| 2904 | }
|
|---|
| 2905 |
|
|---|
| 2906 | /*
|
|---|
| 2907 | *@@ ProcessJumpToAnchorName:
|
|---|
| 2908 | * implementation for TXM_JUMPTOANCHORNAME in fnwpTextView.
|
|---|
| 2909 | *
|
|---|
| 2910 | *@@added V1.0.0 (2002-08-12) [umoeller]
|
|---|
| 2911 | */
|
|---|
| 2912 |
|
|---|
| 2913 | STATIC MRESULT ProcessJumpToAnchorName(HWND hwndTextView, MPARAM mp1)
|
|---|
| 2914 | {
|
|---|
| 2915 | MRESULT mrc = 0;
|
|---|
| 2916 | PTEXTVIEWWINDATA ptxvd;
|
|---|
| 2917 |
|
|---|
| 2918 | if ( (ptxvd = (PTEXTVIEWWINDATA)WinQueryWindowPtr(hwndTextView, QWL_PRIVATE))
|
|---|
| 2919 | && (mp1)
|
|---|
| 2920 | )
|
|---|
| 2921 | {
|
|---|
| 2922 | PLISTNODE pWordNode;
|
|---|
| 2923 | PTXVWORD pWord;
|
|---|
| 2924 | if ( (pWordNode = txvFindWordFromAnchor(&ptxvd->xfd,
|
|---|
| 2925 | (const char*)mp1))
|
|---|
| 2926 | && (pWord = (PTXVWORD)pWordNode->pItemData)
|
|---|
| 2927 | )
|
|---|
| 2928 | {
|
|---|
| 2929 | // found:
|
|---|
| 2930 | PTXVRECTANGLE pRect = pWord->pRectangle;
|
|---|
| 2931 | ULONG ulWinCY = (ptxvd->rclViewText.yTop - ptxvd->rclViewText.yBottom);
|
|---|
| 2932 |
|
|---|
| 2933 | // now we need to scroll the window so that this rectangle is on top.
|
|---|
| 2934 | // Since rectangles start out with the height of the window (e.g. +768)
|
|---|
| 2935 | // and then have lower y coordinates down to way in the negatives,
|
|---|
| 2936 | // to get the y offset, we must...
|
|---|
| 2937 | ptxvd->scrw.ptlScrollOfs.y = (-pRect->rcl.yTop) - ulWinCY;
|
|---|
| 2938 |
|
|---|
| 2939 | if (ptxvd->scrw.ptlScrollOfs.y < 0)
|
|---|
| 2940 | ptxvd->scrw.ptlScrollOfs.y = 0;
|
|---|
| 2941 | if (ptxvd->scrw.ptlScrollOfs.y > ((LONG)ptxvd->xfd.szlWorkspace.cy - ulWinCY))
|
|---|
| 2942 | ptxvd->scrw.ptlScrollOfs.y = (LONG)ptxvd->xfd.szlWorkspace.cy - ulWinCY;
|
|---|
| 2943 |
|
|---|
| 2944 | // vertical scroll bar enabled at all?
|
|---|
| 2945 | if (ptxvd->flStyle & XS_VSCROLL)
|
|---|
| 2946 | {
|
|---|
| 2947 | /* BOOL fEnabled = */ winhUpdateScrollBar(ptxvd->scrw.hwndVScroll,
|
|---|
| 2948 | ulWinCY,
|
|---|
| 2949 | ptxvd->xfd.szlWorkspace.cy,
|
|---|
| 2950 | ptxvd->scrw.ptlScrollOfs.y,
|
|---|
| 2951 | (ptxvd->flStyle & XS_AUTOVHIDE));
|
|---|
| 2952 | WinInvalidateRect(hwndTextView, NULL, FALSE);
|
|---|
| 2953 | }
|
|---|
| 2954 |
|
|---|
| 2955 | mrc = (MRESULT)TRUE;
|
|---|
| 2956 | }
|
|---|
| 2957 | }
|
|---|
| 2958 |
|
|---|
| 2959 | return mrc;
|
|---|
| 2960 | }
|
|---|
| 2961 |
|
|---|
| 2962 | /*
|
|---|
| 2963 | *@@ ProcessDestroy:
|
|---|
| 2964 | * implementation for WM_DESTROY in fnwpTextView.
|
|---|
| 2965 | *
|
|---|
| 2966 | *@@added V1.0.0 (2002-08-12) [umoeller]
|
|---|
| 2967 | */
|
|---|
| 2968 |
|
|---|
| 2969 | STATIC MRESULT ProcessDestroy(HWND hwndTextView, MPARAM mp1, MPARAM mp2)
|
|---|
| 2970 | {
|
|---|
| 2971 | PTEXTVIEWWINDATA ptxvd;
|
|---|
| 2972 |
|
|---|
| 2973 | if (ptxvd = (PTEXTVIEWWINDATA)WinQueryWindowPtr(hwndTextView, QWL_PRIVATE))
|
|---|
| 2974 | {
|
|---|
| 2975 | xstrClear(&ptxvd->xfd.strViewText);
|
|---|
| 2976 | lstClear(&ptxvd->xfd.llRectangles);
|
|---|
| 2977 | lstClear(&ptxvd->xfd.llWords);
|
|---|
| 2978 | GpiDestroyPS(ptxvd->hps);
|
|---|
| 2979 | free(ptxvd);
|
|---|
| 2980 | WinSetWindowPtr(hwndTextView, QWL_PRIVATE, NULL);
|
|---|
| 2981 | }
|
|---|
| 2982 |
|
|---|
| 2983 | return WinDefWindowProc(hwndTextView, WM_DESTROY, mp1, mp2);
|
|---|
| 2984 | }
|
|---|
| 2985 |
|
|---|
| 2986 | /*
|
|---|
| 2987 | *@@ fnwpTextView:
|
|---|
| 2988 | * window procedure for the text view control. This is
|
|---|
| 2989 | * registered with the WC_XTEXTVIEW class in txvRegisterTextView.
|
|---|
| 2990 | *
|
|---|
| 2991 | * The text view control is not a subclassed whatever control,
|
|---|
| 2992 | * but a control implemented from scratch. As a result, we
|
|---|
| 2993 | * had to implement all messages which are usually recognized
|
|---|
| 2994 | * by a control. In detail, we have:
|
|---|
| 2995 | *
|
|---|
| 2996 | * -- WM_WINDOWPOSCHANGED: if the control is resized, the
|
|---|
| 2997 | * text is reformatted and the scroll bars are readjusted.
|
|---|
| 2998 | * See AdjustViewRects and txvFormatText.
|
|---|
| 2999 | *
|
|---|
| 3000 | * -- WM_PRESPARAMCHANGED: if fonts or colors are dropped
|
|---|
| 3001 | * on the control, we reformat the text also.
|
|---|
| 3002 | *
|
|---|
| 3003 | * -- WM_HSCROLL and WM_VSCROLL: this calls winhHandleScrollMsg
|
|---|
| 3004 | * to scroll the window contents.
|
|---|
| 3005 | *
|
|---|
| 3006 | * -- WM_BUTTON1DOWN: this sets the focus to the control.
|
|---|
| 3007 | *
|
|---|
| 3008 | * -- WM_SETFOCUS: if we receive the focus, we draw a fine
|
|---|
| 3009 | * dotted line in the "selection" color around the text
|
|---|
| 3010 | * window.
|
|---|
| 3011 | *
|
|---|
| 3012 | * -- WM_CHAR: if we have the focus, the user can move the
|
|---|
| 3013 | * visible part within the workspace using the usual
|
|---|
| 3014 | * cursor and HOME/END keys.
|
|---|
| 3015 | *
|
|---|
| 3016 | * -- WM_MOUSEMOVE: this sends WM_CONTROLPOINTER to the
|
|---|
| 3017 | * owner so the owner can change the mouse pointer.
|
|---|
| 3018 | *
|
|---|
| 3019 | * <B>Painting</B>
|
|---|
| 3020 | *
|
|---|
| 3021 | * The text view control creates a micro presentation space
|
|---|
| 3022 | * from the window's device context upon WM_CREATE, which is
|
|---|
| 3023 | * stored in TEXTVIEWWINDATA. We do not use WinBeginPaint in
|
|---|
| 3024 | * WM_PAINT, but only the PS we created ourselves. This saves
|
|---|
| 3025 | * us from resetting and researching all the fonts etc., which
|
|---|
| 3026 | * should be speedier.
|
|---|
| 3027 | *
|
|---|
| 3028 | * The text view control uses a private window word for storing
|
|---|
| 3029 | * its own data. The client is free to use QWL_USER of the
|
|---|
| 3030 | * text view control.
|
|---|
| 3031 | *
|
|---|
| 3032 | *@@changed V0.9.3 (2000-05-05) [umoeller]: removed TXM_NEWTEXT; now supporting WinSetWindowText
|
|---|
| 3033 | *@@changed V0.9.3 (2000-05-07) [umoeller]: crashed if create param was NULL; fixed
|
|---|
| 3034 | *@@changed V0.9.20 (2002-08-10) [umoeller]: no longer using QWL_USER, which is free now
|
|---|
| 3035 | *@@changed V0.9.20 (2002-08-10) [umoeller]: setting text on window creation never worked, fixed
|
|---|
| 3036 | *@@changed V0.9.20 (2002-08-10) [umoeller]: added TXN_ANCHORCLICKED owner notify for anchors
|
|---|
| 3037 | *@@changed V0.9.20 (2002-08-10) [umoeller]: converted private style flags to XS_* window style flags
|
|---|
| 3038 | *@@changed V0.9.20 (2002-08-10) [umoeller]: added support for XS_STATIC
|
|---|
| 3039 | *@@changed V0.9.20 (2002-08-10) [umoeller]: added support for formatting HTML and plain text automatically
|
|---|
| 3040 | *@@changed V1.0.0 (2002-08-12) [umoeller]: optimized locality by moving big chunks into subfuncs
|
|---|
| 3041 | *@@changed V1.0.1 (2003-01-25) [umoeller]: adjusted scroll msgs for new handler code
|
|---|
| 3042 | */
|
|---|
| 3043 |
|
|---|
| 3044 | STATIC MRESULT EXPENTRY fnwpTextView(HWND hwndTextView, ULONG msg, MPARAM mp1, MPARAM mp2)
|
|---|
| 3045 | {
|
|---|
| 3046 | MRESULT mrc = 0;
|
|---|
| 3047 | PTEXTVIEWWINDATA ptxvd;
|
|---|
| 3048 |
|
|---|
| 3049 | switch (msg)
|
|---|
| 3050 | {
|
|---|
| 3051 | /*
|
|---|
| 3052 | * WM_CREATE:
|
|---|
| 3053 | *
|
|---|
| 3054 | */
|
|---|
| 3055 |
|
|---|
| 3056 | case WM_CREATE:
|
|---|
| 3057 | mrc = ProcessCreate(hwndTextView, mp1, mp2);
|
|---|
| 3058 | // extracted V1.0.0 (2002-08-12) [umoeller]
|
|---|
| 3059 | break;
|
|---|
| 3060 |
|
|---|
| 3061 | /*
|
|---|
| 3062 | * WM_SETWINDOWPARAMS:
|
|---|
| 3063 | * this message sets the window parameters,
|
|---|
| 3064 | * most importantly, the window text.
|
|---|
| 3065 | *
|
|---|
| 3066 | * This updates the control.
|
|---|
| 3067 | */
|
|---|
| 3068 |
|
|---|
| 3069 | case WM_SETWINDOWPARAMS:
|
|---|
| 3070 | if ( (mp1)
|
|---|
| 3071 | && (((PWNDPARAMS)mp1)->fsStatus & WPM_TEXT)
|
|---|
| 3072 | && (ptxvd = (PTEXTVIEWWINDATA)WinQueryWindowPtr(hwndTextView, QWL_PRIVATE))
|
|---|
| 3073 | )
|
|---|
| 3074 | {
|
|---|
| 3075 | SetWindowText(hwndTextView,
|
|---|
| 3076 | ptxvd,
|
|---|
| 3077 | ((PWNDPARAMS)mp1)->pszText);
|
|---|
| 3078 | mrc = (MRESULT)TRUE; // was missing V0.9.20 (2002-08-10) [umoeller]
|
|---|
| 3079 | }
|
|---|
| 3080 | break;
|
|---|
| 3081 |
|
|---|
| 3082 | /*
|
|---|
| 3083 | * WM_WINDOWPOSCHANGED:
|
|---|
| 3084 | *
|
|---|
| 3085 | */
|
|---|
| 3086 |
|
|---|
| 3087 | case WM_WINDOWPOSCHANGED:
|
|---|
| 3088 | // resizing?
|
|---|
| 3089 | if ( (mp1)
|
|---|
| 3090 | && (((PSWP)mp1)->fl & SWP_SIZE)
|
|---|
| 3091 | && (ptxvd = (PTEXTVIEWWINDATA)WinQueryWindowPtr(hwndTextView, QWL_PRIVATE))
|
|---|
| 3092 | )
|
|---|
| 3093 | {
|
|---|
| 3094 | WinQueryWindowRect(hwndTextView,
|
|---|
| 3095 | &ptxvd->rclViewReal);
|
|---|
| 3096 | AdjustViewRects(hwndTextView,
|
|---|
| 3097 | ptxvd);
|
|---|
| 3098 | FormatText2Screen(hwndTextView,
|
|---|
| 3099 | ptxvd,
|
|---|
| 3100 | FALSE,
|
|---|
| 3101 | FALSE); // quick format
|
|---|
| 3102 | }
|
|---|
| 3103 | break;
|
|---|
| 3104 |
|
|---|
| 3105 | /*
|
|---|
| 3106 | * WM_PAINT:
|
|---|
| 3107 | *
|
|---|
| 3108 | */
|
|---|
| 3109 |
|
|---|
| 3110 | case WM_PAINT:
|
|---|
| 3111 | ProcessPaint(hwndTextView);
|
|---|
| 3112 | // extracted V1.0.0 (2002-08-12) [umoeller]
|
|---|
| 3113 | break;
|
|---|
| 3114 |
|
|---|
| 3115 | /*
|
|---|
| 3116 | * WM_PRESPARAMCHANGED:
|
|---|
| 3117 | *
|
|---|
| 3118 | * Changing the color or font settings
|
|---|
| 3119 | * is equivalent to changing the default
|
|---|
| 3120 | * paragraph format. See TXM_SETFORMAT.
|
|---|
| 3121 | */
|
|---|
| 3122 |
|
|---|
| 3123 | case WM_PRESPARAMCHANGED:
|
|---|
| 3124 | ProcessPresParamChanged(hwndTextView, mp1);
|
|---|
| 3125 | break;
|
|---|
| 3126 |
|
|---|
| 3127 | /*
|
|---|
| 3128 | * WM_VSCROLL:
|
|---|
| 3129 | *
|
|---|
| 3130 | */
|
|---|
| 3131 |
|
|---|
| 3132 | case WM_VSCROLL:
|
|---|
| 3133 | case WM_HSCROLL:
|
|---|
| 3134 | ProcessScroll(hwndTextView, msg, mp2);
|
|---|
| 3135 | // V1.0.1 (2003-01-22) [umoeller]
|
|---|
| 3136 | break;
|
|---|
| 3137 |
|
|---|
| 3138 | /*
|
|---|
| 3139 | * WM_SETFOCUS:
|
|---|
| 3140 | *
|
|---|
| 3141 | */
|
|---|
| 3142 |
|
|---|
| 3143 | case WM_SETFOCUS:
|
|---|
| 3144 | ProcessSetFocus(hwndTextView, mp2);
|
|---|
| 3145 | break;
|
|---|
| 3146 |
|
|---|
| 3147 | /*
|
|---|
| 3148 | * WM_MOUSEMOVE:
|
|---|
| 3149 | * send WM_CONTROLPOINTER to owner.
|
|---|
| 3150 | */
|
|---|
| 3151 |
|
|---|
| 3152 | case WM_MOUSEMOVE:
|
|---|
| 3153 | {
|
|---|
| 3154 | HWND hwndOwner;
|
|---|
| 3155 | if (hwndOwner = WinQueryWindow(hwndTextView, QW_OWNER))
|
|---|
| 3156 | {
|
|---|
| 3157 | HPOINTER hptrSet
|
|---|
| 3158 | = (HPOINTER)WinSendMsg(hwndOwner,
|
|---|
| 3159 | WM_CONTROLPOINTER,
|
|---|
| 3160 | (MPARAM)(LONG)WinQueryWindowUShort(hwndTextView,
|
|---|
| 3161 | QWS_ID),
|
|---|
| 3162 | (MPARAM)WinQuerySysPointer(HWND_DESKTOP,
|
|---|
| 3163 | SPTR_ARROW,
|
|---|
| 3164 | FALSE));
|
|---|
| 3165 | WinSetPointer(HWND_DESKTOP, hptrSet);
|
|---|
| 3166 | }
|
|---|
| 3167 | }
|
|---|
| 3168 | break;
|
|---|
| 3169 |
|
|---|
| 3170 | /*
|
|---|
| 3171 | * WM_BUTTON1DOWN:
|
|---|
| 3172 | *
|
|---|
| 3173 | */
|
|---|
| 3174 |
|
|---|
| 3175 | case WM_BUTTON1DOWN:
|
|---|
| 3176 | mrc = ProcessButton1Down(hwndTextView, mp1);
|
|---|
| 3177 | break;
|
|---|
| 3178 |
|
|---|
| 3179 | /*
|
|---|
| 3180 | * WM_BUTTON1UP:
|
|---|
| 3181 | *
|
|---|
| 3182 | */
|
|---|
| 3183 |
|
|---|
| 3184 | case WM_BUTTON1UP:
|
|---|
| 3185 | mrc = ProcessButton1Up(hwndTextView, mp1);
|
|---|
| 3186 | break;
|
|---|
| 3187 |
|
|---|
| 3188 | /*
|
|---|
| 3189 | * WM_CHAR:
|
|---|
| 3190 | *
|
|---|
| 3191 | */
|
|---|
| 3192 |
|
|---|
| 3193 | case WM_CHAR:
|
|---|
| 3194 | mrc = ProcessChar(hwndTextView, mp1, mp2);
|
|---|
| 3195 | break;
|
|---|
| 3196 |
|
|---|
| 3197 | /*
|
|---|
| 3198 | *@@ TXM_QUERYPARFORMAT:
|
|---|
| 3199 | * this msg can be sent to the text view control
|
|---|
| 3200 | * to retrieve the paragraph format with the
|
|---|
| 3201 | * index specified in mp1.
|
|---|
| 3202 | *
|
|---|
| 3203 | * This must be sent, not posted, to the control.
|
|---|
| 3204 | *
|
|---|
| 3205 | * Parameters:
|
|---|
| 3206 | *
|
|---|
| 3207 | * -- ULONG mp1: index of format to query.
|
|---|
| 3208 | * Must be 0 currently for the standard
|
|---|
| 3209 | * paragraph format.
|
|---|
| 3210 | *
|
|---|
| 3211 | * -- PXFMTPARAGRAPH mp2: pointer to buffer
|
|---|
| 3212 | * which is to receive the formatting
|
|---|
| 3213 | * data.
|
|---|
| 3214 | *
|
|---|
| 3215 | * Returns TRUE if copying was successful.
|
|---|
| 3216 | *
|
|---|
| 3217 | *@@added V0.9.3 (2000-05-06) [umoeller]
|
|---|
| 3218 | */
|
|---|
| 3219 |
|
|---|
| 3220 | case TXM_QUERYPARFORMAT:
|
|---|
| 3221 | if ( (ptxvd = (PTEXTVIEWWINDATA)WinQueryWindowPtr(hwndTextView, QWL_PRIVATE))
|
|---|
| 3222 | && (!mp1)
|
|---|
| 3223 | && (mp2)
|
|---|
| 3224 | )
|
|---|
| 3225 | {
|
|---|
| 3226 | memcpy(mp2,
|
|---|
| 3227 | &ptxvd->xfd.fmtpStandard,
|
|---|
| 3228 | sizeof(XFMTPARAGRAPH));
|
|---|
| 3229 | mrc = (MPARAM)TRUE;
|
|---|
| 3230 | }
|
|---|
| 3231 | break;
|
|---|
| 3232 |
|
|---|
| 3233 | /*
|
|---|
| 3234 | *@@ TXM_SETPARFORMAT:
|
|---|
| 3235 | * reverse to TXM_QUERYPARFORMAT, this sets a
|
|---|
| 3236 | * paragraph format (line spacings, margins
|
|---|
| 3237 | * and such).
|
|---|
| 3238 | *
|
|---|
| 3239 | * This must be sent, not posted, to the control.
|
|---|
| 3240 | *
|
|---|
| 3241 | * Parameters:
|
|---|
| 3242 | *
|
|---|
| 3243 | * -- ULONG mp1: index of format to set.
|
|---|
| 3244 | * Must be 0 currently for the standard
|
|---|
| 3245 | * paragraph format.
|
|---|
| 3246 | *
|
|---|
| 3247 | * -- PXFMTPARAGRAPH mp2: pointer to buffer
|
|---|
| 3248 | * from which to copy formatting data.
|
|---|
| 3249 | * If this pointer is NULL, the format
|
|---|
| 3250 | * is reset to the default.
|
|---|
| 3251 | *
|
|---|
| 3252 | * This reformats the control.
|
|---|
| 3253 | *
|
|---|
| 3254 | *@@added V0.9.3 (2000-05-06) [umoeller]
|
|---|
| 3255 | */
|
|---|
| 3256 |
|
|---|
| 3257 | case TXM_SETPARFORMAT:
|
|---|
| 3258 | if ( (ptxvd = (PTEXTVIEWWINDATA)WinQueryWindowPtr(hwndTextView, QWL_PRIVATE))
|
|---|
| 3259 | && (!mp1)
|
|---|
| 3260 | )
|
|---|
| 3261 | {
|
|---|
| 3262 | if (mp2)
|
|---|
| 3263 | // copy:
|
|---|
| 3264 | memcpy(&ptxvd->xfd.fmtpStandard,
|
|---|
| 3265 | mp2,
|
|---|
| 3266 | sizeof(XFMTPARAGRAPH));
|
|---|
| 3267 | else
|
|---|
| 3268 | // default:
|
|---|
| 3269 | memset(&ptxvd->xfd.fmtpStandard,
|
|---|
| 3270 | 0,
|
|---|
| 3271 | sizeof(XFMTPARAGRAPH));
|
|---|
| 3272 |
|
|---|
| 3273 | FormatText2Screen(hwndTextView,
|
|---|
| 3274 | ptxvd,
|
|---|
| 3275 | FALSE,
|
|---|
| 3276 | TRUE); // full reformat
|
|---|
| 3277 |
|
|---|
| 3278 | mrc = (MPARAM)TRUE;
|
|---|
| 3279 | }
|
|---|
| 3280 | break;
|
|---|
| 3281 |
|
|---|
| 3282 | /*
|
|---|
| 3283 | *@@ TXM_SETWORDWRAP:
|
|---|
| 3284 | * this text view control msg quickly changes
|
|---|
| 3285 | * the word-wrapping style of the default
|
|---|
| 3286 | * paragraph formatting.
|
|---|
| 3287 | *
|
|---|
| 3288 | * This may be sent or posted.
|
|---|
| 3289 | *
|
|---|
| 3290 | * (BOOL)mp1 determines whether word wrapping
|
|---|
| 3291 | * should be turned on or off.
|
|---|
| 3292 | */
|
|---|
| 3293 |
|
|---|
| 3294 | case TXM_SETWORDWRAP:
|
|---|
| 3295 | if (ptxvd = (PTEXTVIEWWINDATA)WinQueryWindowPtr(hwndTextView, QWL_PRIVATE))
|
|---|
| 3296 | {
|
|---|
| 3297 | BOOL ulOldFlFormat = ptxvd->xfd.fmtpStandard.fWordWrap;
|
|---|
| 3298 | ptxvd->xfd.fmtpStandard.fWordWrap = (BOOL)mp1;
|
|---|
| 3299 | if (ptxvd->xfd.fmtpStandard.fWordWrap != ulOldFlFormat)
|
|---|
| 3300 | FormatText2Screen(hwndTextView,
|
|---|
| 3301 | ptxvd,
|
|---|
| 3302 | FALSE,
|
|---|
| 3303 | FALSE); // quick format
|
|---|
| 3304 | }
|
|---|
| 3305 | break;
|
|---|
| 3306 |
|
|---|
| 3307 | /*
|
|---|
| 3308 | *@@ TXM_QUERYCDATA:
|
|---|
| 3309 | * copies the current XTEXTVIEWCDATA
|
|---|
| 3310 | * into the specified buffer.
|
|---|
| 3311 | *
|
|---|
| 3312 | * This must be sent, not posted, to the control.
|
|---|
| 3313 | *
|
|---|
| 3314 | * Parameters:
|
|---|
| 3315 | *
|
|---|
| 3316 | * -- PXTEXTVIEWCDATA mp1: target buffer.
|
|---|
| 3317 | * Before calling this, you MUST specify
|
|---|
| 3318 | * XTEXTVIEWCDATA.cbData.
|
|---|
| 3319 | *
|
|---|
| 3320 | * Returns the bytes that were copied as
|
|---|
| 3321 | * a ULONG.
|
|---|
| 3322 | */
|
|---|
| 3323 |
|
|---|
| 3324 | case TXM_QUERYCDATA:
|
|---|
| 3325 | if ( (ptxvd = (PTEXTVIEWWINDATA)WinQueryWindowPtr(hwndTextView, QWL_PRIVATE))
|
|---|
| 3326 | && (mp1)
|
|---|
| 3327 | )
|
|---|
| 3328 | {
|
|---|
| 3329 | PXTEXTVIEWCDATA pTarget = (PXTEXTVIEWCDATA)mp1;
|
|---|
| 3330 | mrc = (MRESULT)min(pTarget->cbData, sizeof(XTEXTVIEWCDATA));
|
|---|
| 3331 | memcpy(pTarget,
|
|---|
| 3332 | &ptxvd->cdata,
|
|---|
| 3333 | (ULONG)mrc);
|
|---|
| 3334 | }
|
|---|
| 3335 | break;
|
|---|
| 3336 |
|
|---|
| 3337 | /*
|
|---|
| 3338 | *@@ TXM_SETCDATA:
|
|---|
| 3339 | * updates the current XTEXTVIEWCDATA
|
|---|
| 3340 | * with the data from the specified buffer.
|
|---|
| 3341 | *
|
|---|
| 3342 | * This must be sent, not posted, to the control.
|
|---|
| 3343 | *
|
|---|
| 3344 | * Parameters:
|
|---|
| 3345 | *
|
|---|
| 3346 | * -- PXTEXTVIEWCDATA mp1: source buffer.
|
|---|
| 3347 | * Before calling this, you MUST specify
|
|---|
| 3348 | * XTEXTVIEWCDATA.cbData.
|
|---|
| 3349 | *
|
|---|
| 3350 | * Returns the bytes that were copied as
|
|---|
| 3351 | * a ULONG.
|
|---|
| 3352 | *
|
|---|
| 3353 | *@@changed V1.0.0 (2002-08-12) [umoeller]: now returning bytes
|
|---|
| 3354 | */
|
|---|
| 3355 |
|
|---|
| 3356 | case TXM_SETCDATA:
|
|---|
| 3357 | if ( (ptxvd = (PTEXTVIEWWINDATA)WinQueryWindowPtr(hwndTextView, QWL_PRIVATE))
|
|---|
| 3358 | && (mp1)
|
|---|
| 3359 | )
|
|---|
| 3360 | {
|
|---|
| 3361 | PXTEXTVIEWCDATA pSource = (PXTEXTVIEWCDATA)mp1;
|
|---|
| 3362 | mrc = (MRESULT)min(pSource->cbData, sizeof(XTEXTVIEWCDATA));
|
|---|
| 3363 | memcpy(&ptxvd->cdata,
|
|---|
| 3364 | pSource,
|
|---|
| 3365 | (ULONG)mrc);
|
|---|
| 3366 | }
|
|---|
| 3367 | break;
|
|---|
| 3368 |
|
|---|
| 3369 | /*
|
|---|
| 3370 | *@@ TXM_JUMPTOANCHORNAME:
|
|---|
| 3371 | * scrolls the XTextView control contents so that
|
|---|
| 3372 | * the text marked with the specified anchor name
|
|---|
| 3373 | * (TXVESC_ANCHORNAME escape) appears at the top
|
|---|
| 3374 | * of the control.
|
|---|
| 3375 | *
|
|---|
| 3376 | * This must be sent, not posted, to the control.
|
|---|
| 3377 | *
|
|---|
| 3378 | * Parameters:
|
|---|
| 3379 | * -- PSZ mp1: anchor name (e.g. "anchor1").
|
|---|
| 3380 | *
|
|---|
| 3381 | * Returns TRUE if the jump was successful.
|
|---|
| 3382 | *
|
|---|
| 3383 | *@@added V0.9.4 (2000-06-12) [umoeller]
|
|---|
| 3384 | */
|
|---|
| 3385 |
|
|---|
| 3386 | case TXM_JUMPTOANCHORNAME:
|
|---|
| 3387 | mrc = ProcessJumpToAnchorName(hwndTextView, mp1);
|
|---|
| 3388 | break;
|
|---|
| 3389 |
|
|---|
| 3390 | /*
|
|---|
| 3391 | *@@ TXM_QUERYTEXTEXTENT:
|
|---|
| 3392 | * returns the extents of the currently set text,
|
|---|
| 3393 | * that is, the width and height of the internal
|
|---|
| 3394 | * work area, of which the current view rectangle
|
|---|
| 3395 | * displays a subrectangle.
|
|---|
| 3396 | *
|
|---|
| 3397 | * This must be sent, not posted, to the control.
|
|---|
| 3398 | *
|
|---|
| 3399 | * Parameters:
|
|---|
| 3400 | *
|
|---|
| 3401 | * -- PSIZEL mp1: pointer to a SIZEL buffer,
|
|---|
| 3402 | * which receives the extent in the cx and
|
|---|
| 3403 | * cy members. These will be set to null
|
|---|
| 3404 | * values if the control currently has no
|
|---|
| 3405 | * text.
|
|---|
| 3406 | *
|
|---|
| 3407 | * Returns TRUE on success.
|
|---|
| 3408 | *
|
|---|
| 3409 | *@@added V0.9.20 (2002-08-10) [umoeller]
|
|---|
| 3410 | */
|
|---|
| 3411 |
|
|---|
| 3412 | case TXM_QUERYTEXTEXTENT:
|
|---|
| 3413 | if ( (mp1)
|
|---|
| 3414 | && (ptxvd = (PTEXTVIEWWINDATA)WinQueryWindowPtr(hwndTextView, QWL_PRIVATE))
|
|---|
| 3415 | )
|
|---|
| 3416 | {
|
|---|
| 3417 | memcpy((PSIZEL)mp1,
|
|---|
| 3418 | &ptxvd->xfd.szlWorkspace,
|
|---|
| 3419 | sizeof(SIZEL));
|
|---|
| 3420 | mrc = (MRESULT)TRUE;
|
|---|
| 3421 | }
|
|---|
| 3422 | break;
|
|---|
| 3423 |
|
|---|
| 3424 | /*
|
|---|
| 3425 | * WM_DESTROY:
|
|---|
| 3426 | * clean up.
|
|---|
| 3427 | */
|
|---|
| 3428 |
|
|---|
| 3429 | case WM_DESTROY:
|
|---|
| 3430 | mrc = ProcessDestroy(hwndTextView, mp1, mp2);
|
|---|
| 3431 | break;
|
|---|
| 3432 |
|
|---|
| 3433 | default:
|
|---|
| 3434 | mrc = WinDefWindowProc(hwndTextView, msg, mp1, mp2);
|
|---|
| 3435 | }
|
|---|
| 3436 |
|
|---|
| 3437 | return mrc;
|
|---|
| 3438 | }
|
|---|
| 3439 |
|
|---|
| 3440 | /*
|
|---|
| 3441 | *@@ txvRegisterTextView:
|
|---|
| 3442 | * registers the Text View class with PM. Required
|
|---|
| 3443 | * before the text view control can be used.
|
|---|
| 3444 | */
|
|---|
| 3445 |
|
|---|
| 3446 | BOOL txvRegisterTextView(HAB hab)
|
|---|
| 3447 | {
|
|---|
| 3448 | return WinRegisterClass(hab,
|
|---|
| 3449 | WC_XTEXTVIEW,
|
|---|
| 3450 | fnwpTextView,
|
|---|
| 3451 | 0,
|
|---|
| 3452 | 2 * sizeof(PVOID)); // QWL_USER and QWL_PRIVATE
|
|---|
| 3453 | }
|
|---|
| 3454 |
|
|---|
| 3455 | /*
|
|---|
| 3456 | *@@ txvReplaceWithTextView:
|
|---|
| 3457 | * replaces any window with a text view control.
|
|---|
| 3458 | * You must call txvRegisterTextView beforehand.
|
|---|
| 3459 | *
|
|---|
| 3460 | *@@added V0.9.1 (2000-02-13) [umoeller]
|
|---|
| 3461 | */
|
|---|
| 3462 |
|
|---|
| 3463 | HWND txvReplaceWithTextView(HWND hwndParentAndOwner,
|
|---|
| 3464 | USHORT usID,
|
|---|
| 3465 | ULONG flWinStyle,
|
|---|
| 3466 | USHORT usBorder)
|
|---|
| 3467 | {
|
|---|
| 3468 | HWND hwndMLE = WinWindowFromID(hwndParentAndOwner, usID),
|
|---|
| 3469 | hwndTextView = NULLHANDLE;
|
|---|
| 3470 | if (hwndMLE)
|
|---|
| 3471 | {
|
|---|
| 3472 | ULONG ul,
|
|---|
| 3473 | // attrFound,
|
|---|
| 3474 | abValue[32];
|
|---|
| 3475 | SWP swpMLE;
|
|---|
| 3476 | XTEXTVIEWCDATA xtxCData;
|
|---|
| 3477 | PSZ pszFont = winhQueryWindowFont(hwndMLE);
|
|---|
| 3478 | LONG lBackClr = -1,
|
|---|
| 3479 | lForeClr = -1;
|
|---|
| 3480 |
|
|---|
| 3481 | if ((ul = WinQueryPresParam(hwndMLE,
|
|---|
| 3482 | PP_BACKGROUNDCOLOR,
|
|---|
| 3483 | 0,
|
|---|
| 3484 | NULL,
|
|---|
| 3485 | (ULONG)sizeof(abValue),
|
|---|
| 3486 | (PVOID)&abValue,
|
|---|
| 3487 | QPF_NOINHERIT)))
|
|---|
| 3488 | lBackClr = abValue[0];
|
|---|
| 3489 |
|
|---|
| 3490 | if ((ul = WinQueryPresParam(hwndMLE,
|
|---|
| 3491 | PP_FOREGROUNDCOLOR,
|
|---|
| 3492 | 0,
|
|---|
| 3493 | NULL,
|
|---|
| 3494 | (ULONG)sizeof(abValue),
|
|---|
| 3495 | (PVOID)&abValue,
|
|---|
| 3496 | QPF_NOINHERIT)))
|
|---|
| 3497 | lForeClr = abValue[0];
|
|---|
| 3498 |
|
|---|
| 3499 | WinQueryWindowPos(hwndMLE, &swpMLE);
|
|---|
| 3500 |
|
|---|
| 3501 | WinDestroyWindow(hwndMLE);
|
|---|
| 3502 | memset(&xtxCData, 0, sizeof(xtxCData));
|
|---|
| 3503 | xtxCData.cbData = sizeof(xtxCData);
|
|---|
| 3504 | xtxCData.ulXBorder = usBorder;
|
|---|
| 3505 | xtxCData.ulYBorder = usBorder;
|
|---|
| 3506 | hwndTextView = WinCreateWindow(hwndParentAndOwner,
|
|---|
| 3507 | WC_XTEXTVIEW,
|
|---|
| 3508 | "",
|
|---|
| 3509 | flWinStyle,
|
|---|
| 3510 | swpMLE.x,
|
|---|
| 3511 | swpMLE.y,
|
|---|
| 3512 | swpMLE.cx,
|
|---|
| 3513 | swpMLE.cy,
|
|---|
| 3514 | hwndParentAndOwner,
|
|---|
| 3515 | HWND_TOP,
|
|---|
| 3516 | usID,
|
|---|
| 3517 | &xtxCData,
|
|---|
| 3518 | 0);
|
|---|
| 3519 | if (pszFont)
|
|---|
| 3520 | {
|
|---|
| 3521 | winhSetWindowFont(hwndTextView, pszFont);
|
|---|
| 3522 | free(pszFont);
|
|---|
| 3523 | }
|
|---|
| 3524 |
|
|---|
| 3525 | if (lBackClr != -1)
|
|---|
| 3526 | WinSetPresParam(hwndTextView,
|
|---|
| 3527 | PP_BACKGROUNDCOLOR,
|
|---|
| 3528 | sizeof(ULONG),
|
|---|
| 3529 | &lBackClr);
|
|---|
| 3530 | if (lForeClr != -1)
|
|---|
| 3531 | WinSetPresParam(hwndTextView,
|
|---|
| 3532 | PP_FOREGROUNDCOLOR,
|
|---|
| 3533 | sizeof(ULONG),
|
|---|
| 3534 | &lForeClr);
|
|---|
| 3535 | }
|
|---|
| 3536 | return hwndTextView;
|
|---|
| 3537 | }
|
|---|
| 3538 |
|
|---|
| 3539 | /* ******************************************************************
|
|---|
| 3540 | *
|
|---|
| 3541 | * Printer-dependent functions
|
|---|
| 3542 | *
|
|---|
| 3543 | ********************************************************************/
|
|---|
| 3544 |
|
|---|
| 3545 | /*
|
|---|
| 3546 | *@@ prthQueryQueues:
|
|---|
| 3547 | * returns a buffer containing all print queues
|
|---|
| 3548 | * on the system.
|
|---|
| 3549 | *
|
|---|
| 3550 | * This is usually the first step before printing.
|
|---|
| 3551 | * After calling this function, show a dlg to the
|
|---|
| 3552 | * user, allow him to select the printer queue
|
|---|
| 3553 | * to be used. This can then be passed to
|
|---|
| 3554 | * prthCreatePrinterDC.
|
|---|
| 3555 | *
|
|---|
| 3556 | * Use prthFreeBuf to free the returned buffer.
|
|---|
| 3557 | */
|
|---|
| 3558 |
|
|---|
| 3559 | STATIC PRQINFO3* prthEnumQueues(PULONG pulReturned) // out: no. of queues found
|
|---|
| 3560 | {
|
|---|
| 3561 | SPLERR rc;
|
|---|
| 3562 | ULONG cTotal;
|
|---|
| 3563 | ULONG cbNeeded = 0;
|
|---|
| 3564 | PRQINFO3 *pprq3 = NULL;
|
|---|
| 3565 |
|
|---|
| 3566 | // count queues & get number of bytes needed for buffer
|
|---|
| 3567 | rc = SplEnumQueue(NULL, // default computer
|
|---|
| 3568 | 3, // detail level
|
|---|
| 3569 | NULL, // pbuf
|
|---|
| 3570 | 0L, // cbBuf
|
|---|
| 3571 | pulReturned, // out: entries returned
|
|---|
| 3572 | &cTotal, // out: total entries available
|
|---|
| 3573 | &cbNeeded,
|
|---|
| 3574 | NULL); // reserved
|
|---|
| 3575 |
|
|---|
| 3576 | if (!rc && cbNeeded)
|
|---|
| 3577 | {
|
|---|
| 3578 | pprq3 = (PRQINFO3*)malloc(cbNeeded);
|
|---|
| 3579 | if (pprq3)
|
|---|
| 3580 | {
|
|---|
| 3581 | // enum the queues
|
|---|
| 3582 | rc = SplEnumQueue(NULL,
|
|---|
| 3583 | 3,
|
|---|
| 3584 | pprq3,
|
|---|
| 3585 | cbNeeded,
|
|---|
| 3586 | pulReturned,
|
|---|
| 3587 | &cTotal,
|
|---|
| 3588 | &cbNeeded,
|
|---|
| 3589 | NULL);
|
|---|
| 3590 | }
|
|---|
| 3591 | }
|
|---|
| 3592 |
|
|---|
| 3593 | return pprq3;
|
|---|
| 3594 | }
|
|---|
| 3595 |
|
|---|
| 3596 | /*
|
|---|
| 3597 | *@@ prthFreeBuf:
|
|---|
| 3598 | *
|
|---|
| 3599 | */
|
|---|
| 3600 |
|
|---|
| 3601 | STATIC VOID prthFreeBuf(PVOID pprq3)
|
|---|
| 3602 | {
|
|---|
| 3603 | if (pprq3)
|
|---|
| 3604 | free(pprq3);
|
|---|
| 3605 | }
|
|---|
| 3606 |
|
|---|
| 3607 | /*
|
|---|
| 3608 | *@@ prthCreatePrinterDC:
|
|---|
| 3609 | * creates a device context for the printer
|
|---|
| 3610 | * specified by the given printer queue.
|
|---|
| 3611 | *
|
|---|
| 3612 | * As a nifty feature, this returns printer
|
|---|
| 3613 | * device resolution automatically in the
|
|---|
| 3614 | * specified buffer.
|
|---|
| 3615 | *
|
|---|
| 3616 | * Returns NULLHANDLE (== DEV_ERROR) on errors.
|
|---|
| 3617 | *
|
|---|
| 3618 | * Use DevCloseDC to destroy the DC.
|
|---|
| 3619 | *
|
|---|
| 3620 | * Based on print sample by Peter Fitzsimmons, Fri 95-09-29 02:47:16am.
|
|---|
| 3621 | */
|
|---|
| 3622 |
|
|---|
| 3623 | STATIC HDC prthCreatePrinterDC(HAB hab,
|
|---|
| 3624 | PRQINFO3 *pprq3,
|
|---|
| 3625 | PLONG palRes) // out: 2 longs holding horizontal and vertical
|
|---|
| 3626 | // printer resolution in pels per inch
|
|---|
| 3627 | {
|
|---|
| 3628 | HDC hdc = NULLHANDLE;
|
|---|
| 3629 | DEVOPENSTRUC dos;
|
|---|
| 3630 | PSZ p;
|
|---|
| 3631 |
|
|---|
| 3632 | memset(&dos, 0, sizeof(dos));
|
|---|
| 3633 | p = strrchr(pprq3->pszDriverName, '.');
|
|---|
| 3634 | if (p)
|
|---|
| 3635 | *p = 0; // del everything after '.'
|
|---|
| 3636 |
|
|---|
| 3637 | dos.pszLogAddress = pprq3->pszName;
|
|---|
| 3638 | dos.pszDriverName = pprq3->pszDriverName;
|
|---|
| 3639 | dos.pdriv = pprq3->pDriverData;
|
|---|
| 3640 | dos.pszDataType = "PM_Q_STD";
|
|---|
| 3641 | hdc = DevOpenDC(hab,
|
|---|
| 3642 | OD_QUEUED,
|
|---|
| 3643 | "*",
|
|---|
| 3644 | 4L, // count of items in next param
|
|---|
| 3645 | (PDEVOPENDATA)&dos,
|
|---|
| 3646 | 0); // compatible DC
|
|---|
| 3647 |
|
|---|
| 3648 | if (hdc)
|
|---|
| 3649 | DevQueryCaps(hdc,
|
|---|
| 3650 | CAPS_HORIZONTAL_FONT_RES,
|
|---|
| 3651 | 2,
|
|---|
| 3652 | palRes); // buffer
|
|---|
| 3653 |
|
|---|
| 3654 | return hdc;
|
|---|
| 3655 | }
|
|---|
| 3656 |
|
|---|
| 3657 | /*
|
|---|
| 3658 | *@@ prthQueryForms:
|
|---|
| 3659 | * returns a buffer containing all forms
|
|---|
| 3660 | * supported by the specified printer DC.
|
|---|
| 3661 | *
|
|---|
| 3662 | * Use prthFreeBuf to free the returned
|
|---|
| 3663 | * buffer.
|
|---|
| 3664 | *
|
|---|
| 3665 | * HCINFO uses different model spaces for
|
|---|
| 3666 | * the returned info. See PMREF for details.
|
|---|
| 3667 | */
|
|---|
| 3668 |
|
|---|
| 3669 | STATIC HCINFO* prthQueryForms(HDC hdc,
|
|---|
| 3670 | PULONG pulCount)
|
|---|
| 3671 | {
|
|---|
| 3672 | HCINFO *pahci = NULL;
|
|---|
| 3673 |
|
|---|
| 3674 | LONG cForms;
|
|---|
| 3675 |
|
|---|
| 3676 | // get form count
|
|---|
| 3677 | cForms = DevQueryHardcopyCaps(hdc, 0L, 0L, NULL); // phci);
|
|---|
| 3678 | if (cForms)
|
|---|
| 3679 | {
|
|---|
| 3680 | pahci = (HCINFO*)malloc(cForms * sizeof(HCINFO));
|
|---|
| 3681 | if (pahci)
|
|---|
| 3682 | {
|
|---|
| 3683 | *pulCount = DevQueryHardcopyCaps(hdc, 0, cForms, pahci);
|
|---|
| 3684 | }
|
|---|
| 3685 | }
|
|---|
| 3686 |
|
|---|
| 3687 | return pahci;
|
|---|
| 3688 | }
|
|---|
| 3689 |
|
|---|
| 3690 | /*
|
|---|
| 3691 | *@@ prthCreatePS:
|
|---|
| 3692 | * creates a "normal" presentation space from the specified
|
|---|
| 3693 | * printer device context (which can be opened thru
|
|---|
| 3694 | * prthCreatePrinterDC).
|
|---|
| 3695 | *
|
|---|
| 3696 | * Returns NULLHANDLE on errors.
|
|---|
| 3697 | *
|
|---|
| 3698 | * Based on print sample by Peter Fitzsimmons, Fri 95-09-29 02:47:16am.
|
|---|
| 3699 | */
|
|---|
| 3700 |
|
|---|
| 3701 | STATIC HPS prthCreatePS(HAB hab, // in: anchor block
|
|---|
| 3702 | HDC hdc, // in: printer device context
|
|---|
| 3703 | ULONG ulUnits) // in: one of:
|
|---|
| 3704 | // -- PU_PELS
|
|---|
| 3705 | // -- PU_LOMETRIC
|
|---|
| 3706 | // -- PU_HIMETRIC
|
|---|
| 3707 | // -- PU_LOENGLISH
|
|---|
| 3708 | // -- PU_HIENGLISH
|
|---|
| 3709 | // -- PU_TWIPS
|
|---|
| 3710 | {
|
|---|
| 3711 | SIZEL sizel;
|
|---|
| 3712 |
|
|---|
| 3713 | sizel.cx = 0;
|
|---|
| 3714 | sizel.cy = 0;
|
|---|
| 3715 | return GpiCreatePS(hab,
|
|---|
| 3716 | hdc,
|
|---|
| 3717 | &sizel,
|
|---|
| 3718 | ulUnits | GPIA_ASSOC | GPIT_NORMAL);
|
|---|
| 3719 | }
|
|---|
| 3720 |
|
|---|
| 3721 | /*
|
|---|
| 3722 | *@@ prthStartDoc:
|
|---|
| 3723 | * calls DevEscape with DEVESC_STARTDOC.
|
|---|
| 3724 | * This must be called before any painting
|
|---|
| 3725 | * into the HDC's HPS. Any GPI calls made
|
|---|
| 3726 | * before this are ignored.
|
|---|
| 3727 | *
|
|---|
| 3728 | * pszDocTitle appears in the spooler.
|
|---|
| 3729 | */
|
|---|
| 3730 |
|
|---|
| 3731 | STATIC VOID prthStartDoc(HDC hdc,
|
|---|
| 3732 | PSZ pszDocTitle)
|
|---|
| 3733 | {
|
|---|
| 3734 | DevEscape(hdc,
|
|---|
| 3735 | DEVESC_STARTDOC,
|
|---|
| 3736 | strlen(pszDocTitle),
|
|---|
| 3737 | pszDocTitle,
|
|---|
| 3738 | 0L,
|
|---|
| 3739 | 0L);
|
|---|
| 3740 | }
|
|---|
| 3741 |
|
|---|
| 3742 | /*
|
|---|
| 3743 | *@@ prthNextPage:
|
|---|
| 3744 | * calls DevEscape with DEVESC_NEWFRAME.
|
|---|
| 3745 | * Signals when an application has finished writing to a page and wants to
|
|---|
| 3746 | * start a new page. It is similar to GpiErase processing for a screen device
|
|---|
| 3747 | * context, and causes a reset of the attributes. This escape is used with a
|
|---|
| 3748 | * printer device to advance to a new page.
|
|---|
| 3749 | */
|
|---|
| 3750 |
|
|---|
| 3751 | STATIC VOID prthNextPage(HDC hdc)
|
|---|
| 3752 | {
|
|---|
| 3753 | DevEscape(hdc,
|
|---|
| 3754 | DEVESC_NEWFRAME,
|
|---|
| 3755 | 0,
|
|---|
| 3756 | 0,
|
|---|
| 3757 | 0,
|
|---|
| 3758 | 0);
|
|---|
| 3759 | }
|
|---|
| 3760 |
|
|---|
| 3761 | /*
|
|---|
| 3762 | *@@ prthEndDoc:
|
|---|
| 3763 | * calls DevEscape with DEVESC_ENDDOC
|
|---|
| 3764 | * and disassociates the HPS from the HDC.
|
|---|
| 3765 | * Call this right before doing
|
|---|
| 3766 | + GpiDestroyPS(hps);
|
|---|
| 3767 | + DevCloseDC(hdc);
|
|---|
| 3768 | */
|
|---|
| 3769 |
|
|---|
| 3770 | STATIC VOID prthEndDoc(HDC hdc,
|
|---|
| 3771 | HPS hps)
|
|---|
| 3772 | {
|
|---|
| 3773 | DevEscape(hdc, DEVESC_ENDDOC, 0L, 0L, 0, NULL);
|
|---|
| 3774 | GpiAssociate(hps, NULLHANDLE);
|
|---|
| 3775 | }
|
|---|
| 3776 |
|
|---|
| 3777 | /*
|
|---|
| 3778 | *@@ txvPrint:
|
|---|
| 3779 | * this does the actual printing.
|
|---|
| 3780 | */
|
|---|
| 3781 |
|
|---|
| 3782 | BOOL txvPrint(HAB hab,
|
|---|
| 3783 | HDC hdc, // in: printer device context
|
|---|
| 3784 | HPS hps, // in: printer presentation space (using PU_PELS)
|
|---|
| 3785 | PSZ pszViewText, // in: text to print
|
|---|
| 3786 | ULONG ulSize, // in: default font point size
|
|---|
| 3787 | PSZ pszFaceName, // in: default font face name
|
|---|
| 3788 | HCINFO *phci, // in: hardcopy form to use
|
|---|
| 3789 | PSZ pszDocTitle, // in: document title (appears in spooler)
|
|---|
| 3790 | FNPRINTCALLBACK *pfnCallback)
|
|---|
| 3791 | {
|
|---|
| 3792 | RECTL rclPageDevice,
|
|---|
| 3793 | rclPageWorld;
|
|---|
| 3794 | XFORMATDATA xfd;
|
|---|
| 3795 | BOOL fAnotherPage = FALSE;
|
|---|
| 3796 | ULONG ulCurrentLineIndex = 0,
|
|---|
| 3797 | ulCurrentPage = 1;
|
|---|
| 3798 | LONG lCurrentYOfs = 0;
|
|---|
| 3799 |
|
|---|
| 3800 | /* MATRIXLF matlf;
|
|---|
| 3801 | POINTL ptlCenter;
|
|---|
| 3802 | FIXED scalars[2]; */
|
|---|
| 3803 |
|
|---|
| 3804 | // important: we must do a STARTDOC before we use the printer HPS.
|
|---|
| 3805 | prthStartDoc(hdc,
|
|---|
| 3806 | pszDocTitle);
|
|---|
| 3807 |
|
|---|
| 3808 | // the PS is in TWIPS, but our world coordinate
|
|---|
| 3809 | // space is in pels, so we need to transform
|
|---|
| 3810 | /* GpiQueryViewingTransformMatrix(hps,
|
|---|
| 3811 | 1L,
|
|---|
| 3812 | &matlf);
|
|---|
| 3813 | ptlCenter.x = 0;
|
|---|
| 3814 | ptlCenter.y = 0;
|
|---|
| 3815 | scalars[0] = MAKEFIXED(2,0);
|
|---|
| 3816 | scalars[1] = MAKEFIXED(3,0);
|
|---|
| 3817 |
|
|---|
| 3818 | GpiScale (hps,
|
|---|
| 3819 | &matlf,
|
|---|
| 3820 | TRANSFORM_REPLACE,
|
|---|
| 3821 | scalars,
|
|---|
| 3822 | &ptlCenter); */
|
|---|
| 3823 |
|
|---|
| 3824 | // initialize format with font from window
|
|---|
| 3825 | txvInitFormat(&xfd);
|
|---|
| 3826 |
|
|---|
| 3827 | /* SetFormatFont(hps,
|
|---|
| 3828 | &xfd,
|
|---|
| 3829 | ulSize,
|
|---|
| 3830 | pszFaceName); */
|
|---|
| 3831 |
|
|---|
| 3832 | // use text from window
|
|---|
| 3833 | xstrcpy(&xfd.strViewText, pszViewText, 0);
|
|---|
| 3834 |
|
|---|
| 3835 | // setup page
|
|---|
| 3836 | GpiQueryPageViewport(hps,
|
|---|
| 3837 | &rclPageDevice);
|
|---|
| 3838 | // this is in device units; convert this
|
|---|
| 3839 | // to the world coordinate space of the printer PS
|
|---|
| 3840 | memcpy(&rclPageWorld, &rclPageDevice, sizeof(RECTL));
|
|---|
| 3841 | GpiConvert(hps,
|
|---|
| 3842 | CVTC_DEVICE, // source
|
|---|
| 3843 | CVTC_WORLD,
|
|---|
| 3844 | 2, // 2 points, it's a rectangle
|
|---|
| 3845 | (PPOINTL)&rclPageWorld);
|
|---|
| 3846 |
|
|---|
| 3847 | // left and bottom margins are in millimeters...
|
|---|
| 3848 | /* rclPage.xLeft = 100; // ###
|
|---|
| 3849 | rclPage.yBottom = 100;
|
|---|
| 3850 | rclPage.xRight = rclPage.xLeft + phci->xPels;
|
|---|
| 3851 | rclPage.yTop = rclPage.yBottom + phci->yPels; */
|
|---|
| 3852 |
|
|---|
| 3853 | txvFormatText(hps,
|
|---|
| 3854 | &xfd, // in: ptxvd->rclViewText
|
|---|
| 3855 | &rclPageWorld,
|
|---|
| 3856 | TRUE);
|
|---|
| 3857 |
|
|---|
| 3858 | do
|
|---|
| 3859 | {
|
|---|
| 3860 | _Pmpf(("---- printing page %d",
|
|---|
| 3861 | ulCurrentPage));
|
|---|
| 3862 |
|
|---|
| 3863 | fAnotherPage = txvPaintText(hab,
|
|---|
| 3864 | hps,
|
|---|
| 3865 | &xfd,
|
|---|
| 3866 | &rclPageWorld,
|
|---|
| 3867 | 0,
|
|---|
| 3868 | &lCurrentYOfs,
|
|---|
| 3869 | FALSE, // draw only fully visible lines
|
|---|
| 3870 | &ulCurrentLineIndex); // in/out: line to start with
|
|---|
| 3871 | if (fAnotherPage)
|
|---|
| 3872 | {
|
|---|
| 3873 | prthNextPage(hdc);
|
|---|
| 3874 |
|
|---|
| 3875 | if (pfnCallback(ulCurrentPage++, 0) == FALSE)
|
|---|
| 3876 | fAnotherPage = FALSE;
|
|---|
| 3877 | }
|
|---|
| 3878 | } while (fAnotherPage);
|
|---|
| 3879 |
|
|---|
| 3880 | prthEndDoc(hdc, hps);
|
|---|
| 3881 |
|
|---|
| 3882 | return TRUE;
|
|---|
| 3883 | }
|
|---|
| 3884 |
|
|---|
| 3885 | /*
|
|---|
| 3886 | *@@ txvPrintWindow:
|
|---|
| 3887 | * one-shot function which prints the contents
|
|---|
| 3888 | * of the specified XTextView control to the
|
|---|
| 3889 | * default printer, using the default form.
|
|---|
| 3890 | *
|
|---|
| 3891 | * Returns a nonzero value upon errors.
|
|---|
| 3892 | *
|
|---|
| 3893 | * Based on print sample by Peter Fitzsimmons, Fri 95-09-29 02:47:16am.
|
|---|
| 3894 | */
|
|---|
| 3895 |
|
|---|
| 3896 | int txvPrintWindow(HWND hwndTextView,
|
|---|
| 3897 | PSZ pszDocTitle, // in: document title (appears in spooler)
|
|---|
| 3898 | FNPRINTCALLBACK *pfnCallback)
|
|---|
| 3899 | {
|
|---|
| 3900 | int irc = 0;
|
|---|
| 3901 |
|
|---|
| 3902 | PTEXTVIEWWINDATA ptxvd = (PTEXTVIEWWINDATA)WinQueryWindowPtr(hwndTextView, QWL_PRIVATE);
|
|---|
| 3903 |
|
|---|
| 3904 | if (!ptxvd)
|
|---|
| 3905 | irc = 1;
|
|---|
| 3906 | else
|
|---|
| 3907 | {
|
|---|
| 3908 | ULONG cReturned = 0;
|
|---|
| 3909 | PRQINFO3 *pprq3 = prthEnumQueues(&cReturned);
|
|---|
| 3910 | HDC hdc = NULLHANDLE;
|
|---|
| 3911 | LONG caps[2];
|
|---|
| 3912 |
|
|---|
| 3913 | // find default queue
|
|---|
| 3914 | if (pprq3)
|
|---|
| 3915 | {
|
|---|
| 3916 | ULONG i;
|
|---|
| 3917 | // search for default queue;
|
|---|
| 3918 | for (i = 0; i < cReturned; i++)
|
|---|
| 3919 | if (pprq3[i].fsType & PRQ3_TYPE_APPDEFAULT)
|
|---|
| 3920 | {
|
|---|
| 3921 | hdc = prthCreatePrinterDC(ptxvd->hab,
|
|---|
| 3922 | &pprq3[i],
|
|---|
| 3923 | caps);
|
|---|
| 3924 |
|
|---|
| 3925 | break;
|
|---|
| 3926 | }
|
|---|
| 3927 | prthFreeBuf(pprq3);
|
|---|
| 3928 | }
|
|---|
| 3929 |
|
|---|
| 3930 | if (!hdc)
|
|---|
| 3931 | irc = 2;
|
|---|
| 3932 | else
|
|---|
| 3933 | {
|
|---|
| 3934 | // OK, we got a printer DC:
|
|---|
| 3935 | HPS hps;
|
|---|
| 3936 | ULONG cForms = 0;
|
|---|
| 3937 | HCINFO *pahci,
|
|---|
| 3938 | *phciSelected = 0;
|
|---|
| 3939 |
|
|---|
| 3940 | // find default form
|
|---|
| 3941 | pahci = prthQueryForms(hdc,
|
|---|
| 3942 | &cForms);
|
|---|
| 3943 | if (pahci)
|
|---|
| 3944 | {
|
|---|
| 3945 | HCINFO *phciThis = pahci;
|
|---|
| 3946 | ULONG i;
|
|---|
| 3947 | for (i = 0;
|
|---|
| 3948 | i < cForms;
|
|---|
| 3949 | i++, phciThis++)
|
|---|
| 3950 | {
|
|---|
| 3951 | if (phciThis->flAttributes & HCAPS_CURRENT)
|
|---|
| 3952 | {
|
|---|
| 3953 | phciSelected = phciThis;
|
|---|
| 3954 | }
|
|---|
| 3955 | }
|
|---|
| 3956 | }
|
|---|
| 3957 |
|
|---|
| 3958 | if (!phciSelected)
|
|---|
| 3959 | irc = 3;
|
|---|
| 3960 | else
|
|---|
| 3961 | {
|
|---|
| 3962 | // create printer PS
|
|---|
| 3963 | hps = prthCreatePS(ptxvd->hab,
|
|---|
| 3964 | hdc,
|
|---|
| 3965 | PU_PELS);
|
|---|
| 3966 |
|
|---|
| 3967 | if (hps == GPI_ERROR)
|
|---|
| 3968 | irc = 4;
|
|---|
| 3969 | else
|
|---|
| 3970 | {
|
|---|
| 3971 | PSZ pszFont;
|
|---|
| 3972 | ULONG ulSize = 0;
|
|---|
| 3973 | PSZ pszFaceName = 0;
|
|---|
| 3974 |
|
|---|
| 3975 | if ((pszFont = winhQueryWindowFont(hwndTextView)))
|
|---|
| 3976 | gpihSplitPresFont(pszFont,
|
|---|
| 3977 | &ulSize,
|
|---|
| 3978 | &pszFaceName);
|
|---|
| 3979 | txvPrint(ptxvd->hab,
|
|---|
| 3980 | hdc,
|
|---|
| 3981 | hps,
|
|---|
| 3982 | ptxvd->xfd.strViewText.psz,
|
|---|
| 3983 | ulSize,
|
|---|
| 3984 | pszFaceName,
|
|---|
| 3985 | phciSelected,
|
|---|
| 3986 | pszDocTitle,
|
|---|
| 3987 | pfnCallback);
|
|---|
| 3988 |
|
|---|
| 3989 | if (pszFont)
|
|---|
| 3990 | free(pszFont);
|
|---|
| 3991 |
|
|---|
| 3992 | GpiDestroyPS(hps);
|
|---|
| 3993 | }
|
|---|
| 3994 | }
|
|---|
| 3995 | DevCloseDC(hdc);
|
|---|
| 3996 | }
|
|---|
| 3997 | }
|
|---|
| 3998 |
|
|---|
| 3999 | return irc;
|
|---|
| 4000 | }
|
|---|
| 4001 |
|
|---|
| 4002 |
|
|---|