1 /*
2 * Author: William Chia-Wei Cheng (bill.cheng@acm.org)
3 *
4 * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5 *
6 * This file may be distributed under the terms of the Q Public License
7 * as defined by Trolltech AS of Norway and appearing in the file
8 * LICENSE.QPL included in the packaging of this file.
9 *
10 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12 * PURPOSE. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * @(#)$Header: /mm2/home/cvs/bc-src/tgif/text.c,v 1.73 2011/06/14 02:32:19 william Exp $
19 */
20
21 #define _INCLUDE_FROM_TEXT_C_
22
23 #include "tgifdefs.h"
24 #include "cmdids.h"
25
26 #include "attr.e"
27 #include "auxtext.e"
28 #include "choice.e"
29 #include "cmd.e"
30 #include "color.e"
31 #ifndef _NO_KINPUT
32 #include "convkinput.e"
33 #endif /* ~_NO_KINPUT */
34 #include "cutpaste.e"
35 #include "cursor.e"
36 #include "dialog.e"
37 #include "drawing.e"
38 #include "dup.e"
39 #include "edit.e"
40 #include "exec.e"
41 #include "file.e"
42 #include "font.e"
43 #include "grid.e"
44 #include "inmethod.e"
45 #include "mainloop.e"
46 #include "mainmenu.e"
47 #include "mark.e"
48 #include "menu.e"
49 #include "miniline.e"
50 #include "move.e"
51 #include "msg.e"
52 #include "names.e"
53 #ifndef _NO_NKF
54 #include "nkf.e"
55 #endif /* ~_NO_NKF */
56 #include "obj.e"
57 #include "pattern.e"
58 #include "poly.e"
59 #include "prtgif.e"
60 #include "raster.e"
61 #include "rect.e"
62 #include "ruler.e"
63 #include "scroll.e"
64 #include "select.e"
65 #include "setup.e"
66 #include "stretch.e"
67 #include "strtbl.e"
68 #include "text.e"
69 #include "tginssym.e"
70 #include "util.e"
71 #include "wb.e"
72 #include "xbitmap.e"
73 #include "xpixmap.e"
74
75 #define ADVANCE_LEFT (TRUE)
76 #define ADVANCE_RIGHT (FALSE)
77
78 #define POSITION_END (TRUE)
79 #define POSITION_CUR (FALSE)
80
81 int textDrawn=FALSE;
82 int curTextModified=FALSE;
83 int textVSpace=0;
84
85 int textJust=JUST_L;
86 int textCursorShown=FALSE;
87 int textCursorH=14; /* UNSCALED height of the text cursor */
88 int editingText=FALSE; /* editing existing text */
89 int curTextIsNew=FALSE;
90
91 int editTextSize=0;
92
93 int readingTextObject=FALSE;
94
95 float scriptFraction=((float)0.6);
96 char scriptFractionStr[80];
97
98 int deleteNextCharWithDelKey=TRUE;
99 int lengthLimit256InInsertChar=FALSE;
100
101 static struct ObjRec *justDrawnTextObj=NULL;
102
103 struct tagBeforeEditTextInfo {
104 int x, baseline_y;
105 int obbox_w, obbox_h;
106 int first_mini_line_asc;
107 struct BBRec bbox, obbox;
108 } beforeEditTextInfo;
109
110 static int tmpAdjAbsX=0, tmpAdjAbsY=0; /* absolute coordinates */
111 static int curTextMovedAbsX=0, curTextMovedAbsY=0; /* absolute coordinates */
112
113 /* --------------------- DynStr Routines --------------------- */
114
FreeDynStrBuf(dyn_str)115 void FreeDynStrBuf(dyn_str)
116 struct DynStrRec *dyn_str;
117 {
118 if (dyn_str == NULL) return;
119 UtilFree(dyn_str->s);
120 memset(dyn_str, 0, sizeof(struct DynStrRec));
121 }
122
DynStrCpy(dest_dyn_str,src_dyn_str)123 void DynStrCpy(dest_dyn_str, src_dyn_str)
124 struct DynStrRec *dest_dyn_str, *src_dyn_str;
125 {
126 char *psz_new=NULL;
127 int new_sz=src_dyn_str->sz;
128
129 if (new_sz == 0) {
130 #ifdef _TGIF_DBG /* debug, do not translate */
131 TgAssert(FALSE, "src_dyn_str has 0 size in DynStrCpy()", "Fixed");
132 #endif /* _TGIF_DBG */
133 new_sz++;
134 psz_new = (char *)malloc(sizeof(char));
135 if (psz_new == NULL) FailAllocMessage();
136 *psz_new = '\0';
137 } else {
138 psz_new = (char *)malloc(new_sz*sizeof(char));
139 if (psz_new == NULL) FailAllocMessage();
140 strcpy(psz_new, src_dyn_str->s);
141 }
142 if (dest_dyn_str->s != NULL) free(dest_dyn_str->s);
143 dest_dyn_str->s = psz_new;
144 dest_dyn_str->sz = new_sz;
145 }
146
NewDynStr()147 struct DynStrRec *NewDynStr()
148 {
149 struct DynStrRec *new_dyn_str=NULL;
150
151 new_dyn_str = (struct DynStrRec *)malloc(sizeof(struct DynStrRec));
152 if (new_dyn_str == NULL) FailAllocMessage();
153 new_dyn_str->s = NULL;
154 new_dyn_str->sz = 0;
155 return new_dyn_str;
156 }
157
DynStrDup(dyn_str)158 struct DynStrRec *DynStrDup(dyn_str)
159 struct DynStrRec *dyn_str;
160 {
161 struct DynStrRec *new_dyn_str=NULL;
162
163 new_dyn_str = (struct DynStrRec *)malloc(sizeof(struct DynStrRec));
164 if (new_dyn_str == NULL) FailAllocMessage();
165 new_dyn_str->s = NULL;
166 DynStrCpy(new_dyn_str, dyn_str);
167 return new_dyn_str;
168 }
169
DynStrSet(dest_dyn_str,buf)170 void DynStrSet(dest_dyn_str, buf)
171 struct DynStrRec *dest_dyn_str;
172 char *buf;
173 {
174 char *psz_new=NULL;
175 int sz=strlen(buf)+1;
176
177 psz_new = (char*)malloc(sz*sizeof(char));
178 if (psz_new == NULL) FailAllocMessage();
179 strcpy(psz_new, buf);
180 if (dest_dyn_str->s != NULL) free(dest_dyn_str->s);
181 dest_dyn_str->s = psz_new;
182 dest_dyn_str->sz = sz;
183 }
184
185 /* --------------------- Str Routines --------------------- */
186
FreeStr(str_ptr)187 void FreeStr(str_ptr)
188 struct StrRec *str_ptr;
189 {
190 if (str_ptr->dyn_str.s != NULL) free(str_ptr->dyn_str.s);
191 free(str_ptr);
192 }
193
FreeStrList(str_ptr)194 void FreeStrList(str_ptr)
195 struct StrRec *str_ptr;
196 {
197 while (str_ptr != NULL) {
198 struct StrRec *next_str_ptr=str_ptr->next;
199
200 FreeStr(str_ptr);
201 str_ptr = next_str_ptr;
202 }
203 }
204
NewStr()205 struct StrRec *NewStr()
206 {
207 struct StrRec *new_str_ptr=NULL;
208
209 new_str_ptr = (struct StrRec *)malloc(sizeof(struct StrRec));
210 if (new_str_ptr == NULL) FailAllocMessage();
211 memset(new_str_ptr, 0, sizeof(struct StrRec));
212 DynStrSet(&new_str_ptr->dyn_str, "");
213 return new_str_ptr;
214 }
215
216 /* --------------------- Text Routines --------------------- */
217
SetTextHighlight()218 void SetTextHighlight()
219 {
220 textHighlight = (endStrBlock != NULL && (curStrBlock != endStrBlock ||
221 textCurIndex != textEndIndex));
222 }
223
224 typedef struct tagCursorPositionInCurText {
225 struct ObjRec *cur_text_obj;
226 StrBlockInfo *cur_str_block, *end_str_block;
227 int text_cur_index, text_end_index;
228 } CursorPositionInCurTextInfo;
229
230 static CursorPositionInCurTextInfo gstCursorPositionInCurText;
231
SaveCursorPositionInCurText()232 void SaveCursorPositionInCurText()
233 {
234 gstCursorPositionInCurText.cur_text_obj = curTextObj;
235 gstCursorPositionInCurText.cur_str_block = curStrBlock;
236 gstCursorPositionInCurText.end_str_block = endStrBlock;
237 gstCursorPositionInCurText.text_cur_index = textCurIndex;
238 gstCursorPositionInCurText.text_end_index = textEndIndex;
239 }
240
RestoreCursorPositionInCurText()241 void RestoreCursorPositionInCurText()
242 {
243 curTextObj = gstCursorPositionInCurText.cur_text_obj;
244 curStrBlock = gstCursorPositionInCurText.cur_str_block;
245 endStrBlock = gstCursorPositionInCurText.end_str_block;
246 textCurIndex = gstCursorPositionInCurText.text_cur_index;
247 textEndIndex = gstCursorPositionInCurText.text_end_index;
248 SetTextHighlight();
249 }
250
InvalidateTextCache(text_ptr)251 void InvalidateTextCache(text_ptr)
252 struct TextRec *text_ptr;
253 {
254 if (text_ptr->cached_bitmap != None) {
255 XFreePixmap(mainDisplay, text_ptr->cached_bitmap);
256 }
257 if (text_ptr->cached_pixmap != None) {
258 XFreePixmap(mainDisplay, text_ptr->cached_pixmap);
259 }
260 if (text_ptr->cached_bg_bitmap != None) {
261 XFreePixmap(mainDisplay, text_ptr->cached_bg_bitmap);
262 }
263 text_ptr->cached_zoom = 0;
264 text_ptr->cached_bitmap = None;
265 text_ptr->cached_pixmap = None;
266 text_ptr->cached_bg_bitmap = None;
267 }
268
TellTextCursorPosition(pnX,pnY)269 void TellTextCursorPosition(pnX, pnY)
270 int *pnX, *pnY;
271 {
272 *pnX = textCurX;
273 *pnY = textCurY + textCursorH;
274 }
275
276 #define BLUR 32
277
BlurText(Win,gc,XOff,YOff,W,H)278 void BlurText(Win, gc, XOff, YOff, W, H)
279 Window Win;
280 GC gc;
281 int XOff, YOff, W, H;
282 /* XOff and YOff are screen offsets (scaled and translated) */
283 {
284 XPoint v[5];
285
286 v[0].x = (short)XOff; v[0].y = (short)YOff;
287 v[1].x = (short)XOff; v[1].y = (short)YOff+H+1;
288 v[2].x = (short)XOff+W+1; v[2].y = (short)YOff+H+1;
289 v[3].x = (short)XOff+W+1; v[3].y = (short)YOff;
290 v[4].x = (short)XOff; v[4].y = (short)YOff;
291
292 XFillPolygon(mainDisplay, Win, gc, v, 5, Convex, CoordModeOrigin);
293 }
294
InitText()295 void InitText()
296 {
297 char *c_ptr=NULL;
298 XGCValues values;
299
300 textBackingBitmap = XCreatePixmap(mainDisplay,mainWindow,10,10,1);
301 if (textBackingBitmap==None) {
302 sprintf(gszMsgBox, TgLoadString(STID_CANT_ALLOC_BITMAP_OF_SIZE), 10, 10);
303 Error("InitText()", gszMsgBox);
304 }
305 textBackingBgBitmap = XCreatePixmap(mainDisplay,mainWindow,10,10,1);
306 if (textBackingBgBitmap==None) {
307 sprintf(gszMsgBox, TgLoadString(STID_CANT_ALLOC_BITMAP_OF_SIZE), 10, 10);
308 Error("InitText()", gszMsgBox);
309 }
310 textBackingPixmap = XCreatePixmap(mainDisplay,mainWindow,10,10,mainDepth);
311 if (textBackingPixmap==None) {
312 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_ALLOC_PIXMAP_OF_SIZE), 10,
313 10);
314 Error("InitText()", gszMsgBox);
315 }
316 textBackingBitmapW = 10;
317 textBackingBitmapH = 10;
318
319 values.foreground = 1;
320 values.background = 0;
321 values.fill_style = FillSolid;
322 values.function = GXcopy;
323 rotateGC = XCreateGC(mainDisplay, textBackingBitmap,
324 GCForeground | GCBackground | GCFillStyle | GCFunction,
325 &values);
326 if (rotateGC==NULL) {
327 Error("InitText()", TgLoadString(STID_CANNOT_CREATE_GC));
328 }
329 scriptFraction = 0.6;
330 strcpy(scriptFractionStr, "0.6");
331 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"ScriptFraction")) != NULL) {
332 strcpy(scriptFractionStr, c_ptr);
333 scriptFraction = (float)atof(c_ptr);
334 if (scriptFraction < 0.2 || scriptFraction > 1.01) {
335 fprintf(stderr, TgLoadString(STID_INVALID_XDEF_USE_ALT_STR),
336 TOOL_NAME, "ScriptFraction", scriptFractionStr, "0.6");
337 fprintf(stderr, "\n");
338 scriptFraction = 0.6;
339 strcpy(scriptFractionStr, "0.6");
340 } else if (strcmp(scriptFractionStr, "0.6") == 0) {
341 scriptFraction = 0.6;
342 strcpy(scriptFractionStr, "0.6");
343 }
344 }
345 deleteNextCharWithDelKey = TRUE;
346 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"DeleteNextCharWithDelKey")) !=
347 NULL && UtilStrICmp("false", c_ptr) == 0) {
348 deleteNextCharWithDelKey = FALSE;
349 }
350 lengthLimit256InInsertChar = FALSE;
351 if ((c_ptr=XGetDefault(mainDisplay, TOOL_NAME,
352 "LengthLimit256InInsertChar")) != NULL &&
353 UtilStrICmp("true", c_ptr) == 0) {
354 lengthLimit256InInsertChar = TRUE;
355 }
356 }
357
CleanUpText()358 void CleanUpText()
359 {
360 if (textBackingBitmap != None) {
361 XFreePixmap(mainDisplay, textBackingBitmap);
362 }
363 if (textBackingBgBitmap != None) {
364 XFreePixmap(mainDisplay, textBackingBgBitmap);
365 }
366 if (textBackingPixmap != None) {
367 XFreePixmap(mainDisplay, textBackingPixmap);
368 }
369 textBackingBitmap = None;
370 textBackingBitmapW = textBackingBitmapH = 0;
371 if (rotateGC != NULL) XFreeGC(mainDisplay, rotateGC);
372 rotateGC = NULL;
373 }
374
375 static struct BBRec editTextAreaBBox; /* coordinates are screen offsets */
376
377 static
SetEditTextArea(w,h,min_lbearing,max_rextra)378 void SetEditTextArea(w, h, min_lbearing, max_rextra)
379 int w, h, min_lbearing, max_rextra;
380 {
381 memset(&editTextAreaBBox, 0, sizeof(struct BBRec));
382 SetBBRec(&editTextAreaBBox,
383 textOrigX, textOrigY, textOrigX+w, textOrigY+h);
384 textW = w;
385 textH = h;
386 textAbsMinLBearing = min_lbearing;
387 textAbsMaxRExtra = max_rextra;
388 }
389
390 static
UpdateEditTextArea(w,h,min_lbearing,max_rextra)391 void UpdateEditTextArea(w, h, min_lbearing, max_rextra)
392 int w, h, min_lbearing, max_rextra;
393 {
394 struct BBRec bbox;
395 int text_area_enlarged=FALSE;
396
397 SetBBRec(&bbox, textOrigX, textOrigY, textOrigX+w, textOrigY+h);
398 UnionRect(&editTextAreaBBox, &bbox, &editTextAreaBBox);
399 w = editTextAreaBBox.rbx-editTextAreaBBox.ltx;
400 h = editTextAreaBBox.rby-editTextAreaBBox.lty;
401
402 if (w > textW) {
403 textW = w;
404 text_area_enlarged = TRUE;
405 }
406 if (h > textH) {
407 textH = h;
408 text_area_enlarged = TRUE;
409 }
410 if (min_lbearing < textAbsMinLBearing) {
411 textAbsMinLBearing = min_lbearing;
412 text_area_enlarged = TRUE;
413 }
414 if (max_rextra > textAbsMaxRExtra) {
415 textAbsMaxRExtra = max_rextra;
416 text_area_enlarged = TRUE;
417 }
418 if (text_area_enlarged) {
419 ForceDirtyBBoxToRedrawAll();
420 }
421 }
422
423 static
AdjTextVerticalShift(clean_bbox)424 void AdjTextVerticalShift(clean_bbox)
425 int clean_bbox;
426 {
427 struct TextRec *text_ptr=curTextObj->detail.t;
428 int w=0, h=0, saved_first_miniline_asc=0, new_first_miniline_asc=0;
429
430 saved_first_miniline_asc = text_ptr->minilines.first->asc;
431
432 UpdTextBBox(curTextObj);
433
434 new_first_miniline_asc = text_ptr->minilines.first->asc;
435 if (new_first_miniline_asc > saved_first_miniline_asc) {
436 int saved_orig_y=textOrigY;
437
438 textAbsY = textAbsBaselineY - new_first_miniline_asc;
439 textOrigY = OFFSET_Y(textAbsY);
440 textCurY += (textOrigY - saved_orig_y);
441 }
442 w = text_ptr->minilines.w;
443 h = (textOrigBaselineY - textOrigY) +
444 (text_ptr->minilines.h - new_first_miniline_asc);
445
446 SetTextCurXY();
447 if (textHighlight) SetTextEndXY();
448
449 UpdateEditTextArea(w, h, text_ptr->minilines.min_lbearing,
450 text_ptr->minilines.max_rextra);
451 UpdateCurTextBBoxes(clean_bbox);
452 }
453
NewCurText()454 void NewCurText()
455 {
456 MiniLinesInfo *minilines=NULL;
457 struct TextRec *text_ptr=NULL;
458
459 if (textCursorH+textVSpace <= 0) {
460 textVSpace = 0;
461 ShowTextVSpace();
462 MsgBox(TgLoadString(STID_TEXT_VSPACE_TOO_SMALL_RESET_0), TOOL_NAME,
463 INFO_MB);
464 }
465 PushCurFont();
466
467 text_ptr = (struct TextRec *)malloc(sizeof(struct TextRec));
468 if (text_ptr == NULL) FailAllocMessage();
469 memset(text_ptr, 0, sizeof(struct TextRec));
470
471 minilines = (&text_ptr->minilines);
472
473 CreateMiniLineFromString("", &minilines->first, &minilines->last);
474
475 text_ptr->attr = NULL;
476
477 minilines->just = textJust;
478 minilines->v_space = textVSpace;
479 minilines->first->asc = canvasFontAsc;
480 minilines->first->des = canvasFontDes;
481
482 text_ptr->pen = penPat;
483 text_ptr->fill = objFill;
484 text_ptr->cached_bitmap = None;
485 text_ptr->cached_zoom = 0;
486 text_ptr->lines = 1;
487
488 curStrBlock = minilines->first->first_block;
489 textCurIndex = 0;
490 ResetOnCursorKey(FALSE);
491
492 text_ptr->read_only = FALSE;
493 text_ptr->orig_w = text_ptr->orig_h = 0;
494
495 text_ptr->underline_y_offset = curUnderlineYOffset;
496 text_ptr->overline_y_offset = curOverlineYOffset;
497 text_ptr->min_lbearing = 0;
498 text_ptr->max_rextra = 0;
499 text_ptr->baseline_y = textAbsBaselineY;
500
501 curTextObj = (struct ObjRec *)malloc(sizeof(struct ObjRec));
502 if (curTextObj == NULL) FailAllocMessage();
503 memset(curTextObj, 0, sizeof(struct ObjRec));
504 curTextObj->x = textAbsX;
505 curTextObj->y = textAbsY;
506 curTextObj->type = OBJ_TEXT;
507 curTextObj->id = objId++;
508 curTextObj->dirty = FALSE;
509 curTextObj->rotation = 0;
510 curTextObj->locked = FALSE;
511 /* the color specifies the fill pattern color */
512 curTextObj->color = colorIndex;
513 if (mainDisplay != NULL) {
514 UtilStrCpyN(curTextObj->color_str, sizeof(curTextObj->color_str),
515 colorMenuItems[colorIndex]);
516 }
517 curTextObj->detail.t = text_ptr;
518 curTextObj->fattr = curTextObj->lattr = NULL;
519 curTextObj->ctm = NULL;
520 curTextObj->invisible = FALSE;
521 curTextObj->trans_pat = transPat;
522 AddObj(NULL, topObj, curTextObj);
523
524 SetEditTextArea(0, textCursorH, 0, 0);
525
526 textCursorShown = TRUE;
527 SetTextHighlight();
528 UpdatePinnedMenu(MENU_EDIT);
529
530 curTextIsNew = TRUE;
531
532 if (editTextSize != 0) {
533 RestoreEditTextSize(curTextObj, FALSE);
534 }
535 AdjTextVerticalShift(TRUE);
536
537 if (gnInputMethod != TGIM_NONE) {
538 if (!tgIMHandleNewCurText(mainDisplay, drawWindow)) {
539 }
540 }
541 }
542
FreeTextObj(ObjPtr)543 void FreeTextObj(ObjPtr)
544 struct ObjRec *ObjPtr;
545 {
546 if (ObjPtr->detail.t != NULL) {
547 FreeMiniLines(&ObjPtr->detail.t->minilines, FALSE);
548 if (ObjPtr->detail.t->cached_bitmap != None) {
549 XFreePixmap(mainDisplay, ObjPtr->detail.t->cached_bitmap);
550 }
551 if (ObjPtr->detail.t->cached_pixmap != None) {
552 XFreePixmap(mainDisplay, ObjPtr->detail.t->cached_pixmap);
553 }
554 if (ObjPtr->detail.t->cached_bg_bitmap != None) {
555 XFreePixmap(mainDisplay, ObjPtr->detail.t->cached_bg_bitmap);
556 }
557 free(ObjPtr->detail.t);
558 }
559 free(ObjPtr);
560 }
561
562 static
ShowTextRelatedInfo()563 void ShowTextRelatedInfo()
564 {
565 ShowJust();
566 ShowPen();
567 ShowFill();
568 ShowTransPatMode();
569 ShowColor(FALSE);
570 ShowTextVSpace();
571 ShowCurFont();
572 ShowTextSize();
573 }
574
SetEditTextSizeValue(new_edit_text_size)575 void SetEditTextSizeValue(new_edit_text_size)
576 int new_edit_text_size;
577 {
578 editTextSize = new_edit_text_size;
579 curRealSzUnit = INVALID;
580 }
581
UpdateTextInfoChoices(forced)582 void UpdateTextInfoChoices(forced)
583 int forced;
584 {
585 int saved_font=curFont, saved_style=curStyle, saved_sz_unit=curSzUnit;
586 int saved_just=textJust, saved_color=colorIndex;
587 int saved_underline_on=curUnderlineOn;
588 int saved_overline_on=curOverlineOn;
589 StrSegInfo *pStrSeg=curStrBlock->seg;
590 MiniLinesInfo *minilines=curStrBlock->owner_mini_line->owner_minilines;
591
592 if (!forced && pStrSeg->color == colorIndex &&
593 /* pStrSeg->underline_on == curUnderlineOn && */
594 minilines->just == textJust &&
595 minilines->v_space == textVSpace &&
596 pStrSeg->font == curFont &&
597 pStrSeg->style == curStyle &&
598 pStrSeg->sz_unit == curSzUnit &&
599 (editTextSize == 0 || pStrSeg->real_sz_unit == curRealSzUnit) &&
600 pStrSeg->underline_on == curUnderlineOn &&
601 pStrSeg->overline_on == curOverlineOn) {
602 return;
603 }
604 if (pStrSeg->color != colorIndex) {
605 colorIndex = pStrSeg->color;
606 ShowColor(FALSE);
607 }
608 if (minilines->just != textJust) {
609 textJust = minilines->just;
610 ShowJust();
611 }
612 if (minilines->v_space != textVSpace) {
613 textVSpace = minilines->v_space;
614 ShowTextVSpace();
615 }
616 if (editTextSize != 0) {
617 saved_sz_unit = curRealSzUnit;
618
619 if (forced || curRealSzUnit == INVALID ||
620 pStrSeg->font != curFont || pStrSeg->style != curStyle ||
621 pStrSeg->real_sz_unit != curRealSzUnit ||
622 pStrSeg->sz_unit != curSzUnit ||
623 pStrSeg->underline_on != curUnderlineOn ||
624 pStrSeg->overline_on != curOverlineOn) {
625 if (!TrySetCanvasFont(pStrSeg->font, pStrSeg->style, editTextSize,
626 TRUE, NULL)) {
627 SetEditTextSizeValue(0);
628 } else {
629 if (pStrSeg->font != curFont) curFont = pStrSeg->font;
630 if (pStrSeg->style != curStyle) curStyle = pStrSeg->style;
631 if (pStrSeg->real_sz_unit != curRealSzUnit) {
632 curRealSzUnit = pStrSeg->real_sz_unit;
633 }
634 if (pStrSeg->underline_on != curUnderlineOn) {
635 curUnderlineOn = pStrSeg->underline_on;
636 }
637 if (pStrSeg->overline_on != curOverlineOn) {
638 curOverlineOn = pStrSeg->overline_on;
639 }
640 curSzUnit = FontSizeToSzUnit(editTextSize);
641 SetCanvasFont();
642 ShowTextSize();
643 ShowCurFont();
644 if (!textHighlight) CurFontMsg(FALSE, TRUE, pStrSeg);
645 }
646 }
647 }
648 if (editTextSize == 0) {
649 if (forced || pStrSeg->font != curFont || pStrSeg->style != curStyle ||
650 pStrSeg->sz_unit != curSzUnit ||
651 pStrSeg->underline_on != curUnderlineOn ||
652 pStrSeg->overline_on != curOverlineOn) {
653 if (pStrSeg->font != curFont) curFont = pStrSeg->font;
654 if (pStrSeg->style != curStyle) curStyle = pStrSeg->style;
655 if (pStrSeg->sz_unit != curSzUnit) curSzUnit = pStrSeg->sz_unit;
656 if (pStrSeg->underline_on != curUnderlineOn) {
657 curUnderlineOn = pStrSeg->underline_on;
658 }
659 if (pStrSeg->overline_on != curOverlineOn) {
660 curOverlineOn = pStrSeg->overline_on;
661 }
662 SetCanvasFont();
663 ShowTextSize();
664 ShowCurFont();
665 if (!textHighlight) CurFontMsg(FALSE, TRUE, NULL);
666 }
667 }
668 if (pStrSeg->underline_on != curUnderlineOn) {
669 curUnderlineOn = pStrSeg->underline_on;
670 }
671 if (pStrSeg->overline_on != curOverlineOn) {
672 curOverlineOn = pStrSeg->overline_on;
673 }
674 if (saved_style != curStyle || saved_just != textJust ||
675 saved_underline_on != curUnderlineOn ||
676 saved_overline_on != curOverlineOn) {
677 UpdatePinnedMenu(MENU_STYLE);
678 }
679 if (saved_font != curFont) UpdatePinnedMenu(MENU_FONT);
680 if (editTextSize != 0) {
681 if (saved_sz_unit != curRealSzUnit) {
682 UpdatePinnedMenu(MENU_SIZE);
683 }
684 } else {
685 if (saved_sz_unit != curSzUnit) {
686 UpdatePinnedMenu(MENU_SIZE);
687 }
688 }
689 if (saved_color != colorIndex) UpdatePinnedMenu(MENU_COLOR);
690 }
691
692 static
RestoreStrSegFromUsingEditTextSize(pStrSeg,pUserData)693 void RestoreStrSegFromUsingEditTextSize(pStrSeg, pUserData)
694 StrSegInfo *pStrSeg;
695 void *pUserData; /* NULL */
696 {
697 pStrSeg->sz_unit = pStrSeg->real_sz_unit;
698 }
699
700 static
SaveStrSegToUseEditTextSize(pStrSeg,pUserData)701 void SaveStrSegToUseEditTextSize(pStrSeg, pUserData)
702 StrSegInfo *pStrSeg;
703 void *pUserData; /* NULL */
704 {
705 pStrSeg->real_sz_unit = pStrSeg->sz_unit;
706 pStrSeg->sz_unit = FontSizeToSzUnit(editTextSize);
707 }
708
RestoreEditTextSize(obj_ptr,restore)709 int RestoreEditTextSize(obj_ptr, restore)
710 struct ObjRec *obj_ptr;
711 int restore;
712 /* returns TRUE if something is changed */
713 {
714 if (editTextSize != 0) {
715 MiniLinesInfo *minilines=(&obj_ptr->detail.t->minilines);
716
717 if (restore) {
718 DoFuncOnStrSegForMiniLines(minilines,
719 RestoreStrSegFromUsingEditTextSize, NULL);
720 } else {
721 DoFuncOnStrSegForMiniLines(minilines, SaveStrSegToUseEditTextSize,
722 NULL);
723 }
724 return TRUE;
725 }
726 return FALSE;
727 }
728
ShouldRightMarginBeActive()729 int ShouldRightMarginBeActive()
730 {
731 if (curChoice != DRAWTEXT) return TRUE;
732 if (!textCursorShown) return TRUE;
733
734 if (curTextObj->ctm != NULL) return FALSE;
735 if (textJust != JUST_L) return FALSE;
736 if (curStrBlock->owner_mini_line->owner_minilines->owner_block != NULL) {
737 return FALSE;
738 }
739 if (zoomScale != 0 || zoomedIn) return FALSE;
740 if (editTextSize != 0) return FALSE;
741 if (curStrBlock->next != NULL) return FALSE;
742 if (curStrBlock->type != SB_SIMPLE) return FALSE;
743 if (textCurIndex != curStrBlock->seg->dyn_str.sz-1) return FALSE;
744
745 return TRUE;
746 }
747
SetRightMarginActive()748 void SetRightMarginActive()
749 {
750 if (rightMarginEnabled == TRUE) {
751 int saved_right_margin_active=rightMarginActive;
752
753 rightMarginActive = ShouldRightMarginBeActive();
754 if (rightMarginActive != saved_right_margin_active) {
755 RedrawHRulerWindow();
756 }
757 } else {
758 rightMarginActive = TRUE;
759 }
760 }
761
762 static int gnDontRedrawDuringPaste=FALSE;
763 static int gnPastingLineNum=0;
764
765 static
EndChangeCurText(clean_bbox)766 void EndChangeCurText(clean_bbox)
767 int clean_bbox;
768 {
769 curTextModified = TRUE;
770 if (!gnDontRedrawDuringPaste) {
771 /*
772 * If clean_bbox is TRUE, AdjTextVerticalShift() will adjust
773 * curStrBlock->bbox to be the new size. After
774 * UpdateTextInfoChoices() is called, curStrBlock->clean_bbox
775 * will also be updated to the new size.
776 */
777 AdjTextVerticalShift(clean_bbox);
778
779 RedrawCurText();
780 UpdateTextInfoChoices(FALSE);
781 }
782 InvalidateTextCache(curTextObj->detail.t);
783 }
784
785 static
NumLinesInCurText()786 int NumLinesInCurText()
787 {
788 MiniLinesInfo *minilines=(&curTextObj->detail.t->minilines);
789 MiniLineInfo *pMiniLine=NULL;
790 int count=0;
791
792 for (pMiniLine=minilines->first; pMiniLine != NULL;
793 pMiniLine=pMiniLine->next, count++) {
794 }
795 return count;
796 }
797
798 static
CreateNoTextObj()799 void CreateNoTextObj()
800 {
801 struct TextRec *text_ptr=curTextObj->detail.t;
802 struct AttrRec *attr_ptr=text_ptr->attr;
803 int ltx=0, lty=0, rbx=0, rby=0, scr_ltx=0, scr_lty;
804
805 if (attr_ptr != NULL) {
806 /* the text being edited is an attribute */
807 if (attr_ptr->nameshown) {
808 UnlinkAttr(attr_ptr);
809 FreeTextObj(curTextObj);
810 FreeAttr(attr_ptr);
811 } else {
812 text_ptr->lines = 1;
813 UpdateAttr(text_ptr, attr_ptr);
814 }
815 AdjObjBBox(attr_ptr->owner);
816 if (outerSel != NULL) AdjAncestorsBBox();
817 if (curTextModified) {
818 if (outerSel != NULL) {
819 RecordReplaceAnObj(outerSel->obj);
820 } else {
821 RecordReplaceAnObj(attr_ptr->owner);
822 }
823 } else {
824 AbortPrepareCmd(CMD_REPLACE);
825 }
826 } else {
827 if (outerSel != NULL) {
828 UnlinkCurTextFromInnerSel();
829 AdjAncestorsBBox();
830 }
831 if (!curTextIsNew) {
832 if (outerSel != NULL) {
833 RecordReplaceAnObj(outerSel->obj);
834 } else {
835 ChangeReplaceOneCmdToDeleteCmd();
836 }
837 } else {
838 AbortPrepareCmd(CMD_REPLACE);
839 }
840 if (curTextObj != NULL) {
841 if (outerSel != NULL) {
842 /* curTextObj already broken off from the main */
843 /* stream of objects, so just free it. */
844 FreeObj(curTextObj);
845 } else {
846 DelObj(curTextObj);
847 }
848 }
849 }
850 switch (textJust) {
851 case JUST_L:
852 scr_ltx = OFFSET_X(textAbsX-2);
853 if (zoomedIn) {
854 ltx = ABS_X(textOrigX-2)-2;
855 rbx = ABS_X(textOrigX+textW+2)+2;
856 } else {
857 ltx = ABS_X(textOrigX-4);
858 rbx = ABS_X(textOrigX+textW+4);
859 }
860 break;
861 case JUST_C:
862 scr_ltx = OFFSET_X(textAbsX)-textW/2-2;
863 if (zoomedIn) {
864 ltx = ABS_X(textOrigX-(textW>>1)-2)-2;
865 rbx = ABS_X(textOrigX+(textW>>1)+2)+2;
866 } else {
867 ltx = ABS_X(textOrigX-(textW>>1)-4);
868 rbx = ABS_X(textOrigX+(textW>>1)+4);
869 }
870 break;
871 case JUST_R:
872 scr_ltx = OFFSET_X(textAbsX)-textW-2;
873 if (zoomedIn) {
874 ltx = ABS_X(textOrigX-textW-2)-2;
875 rbx = ABS_X(textOrigX+textW+2)+2;
876 } else {
877 ltx = ABS_X(textOrigX-textW-4);
878 rbx = ABS_X(textOrigX+textW+4);
879 }
880 break;
881 }
882 scr_lty = OFFSET_Y(textAbsY)-2;
883 if (zoomedIn) {
884 lty = ABS_Y(textOrigY-2)-2;
885 rby = ABS_Y(textOrigY+textH+2)+2;
886 } else {
887 lty = ABS_Y(textOrigY-4);
888 rby = ABS_Y(textOrigY+textH+4);
889 }
890 ltx -= (curTextOutlineHalfW<<1);
891 lty -= (curTextOutlineHalfW<<1);
892 rbx += (curTextOutlineHalfW<<2);
893 rby += (curTextOutlineHalfW<<2);
894 if (editingText) {
895 XClearArea(mainDisplay, drawWindow,
896 scr_ltx-(curTextOutlineHalfW<<1), scr_lty-(curTextOutlineHalfW<<1),
897 textW+5+(curTextOutlineHalfW<<2), textH+5+(curTextOutlineHalfW<<2),
898 FALSE);
899 RedrawAreas(botObj, beforeEditTextInfo.bbox.ltx-GRID_ABS_SIZE(2),
900 beforeEditTextInfo.bbox.lty-GRID_ABS_SIZE(2),
901 beforeEditTextInfo.bbox.rbx+GRID_ABS_SIZE(2),
902 beforeEditTextInfo.bbox.rby+GRID_ABS_SIZE(2),
903 ltx, lty, rbx, rby);
904 } else {
905 RedrawAnArea(botObj, ltx, lty, rbx, rby);
906 }
907 firstMiniLine = lastMiniLine = NULL;
908 textCursorShown = FALSE;
909 curTextObj = NULL;
910 textCurIndex = 0;
911
912 SetEditTextArea(0, textCursorH, 0, 0);
913
914 if (editingText) {
915 XClearArea(mainDisplay, drawWindow,
916 scr_ltx-(curTextOutlineHalfW<<1), scr_lty-(curTextOutlineHalfW<<1),
917 textW+5+(curTextOutlineHalfW<<2), textH+5+(curTextOutlineHalfW<<2),
918 FALSE);
919 RedrawAreas(botObj, beforeEditTextInfo.bbox.ltx-GRID_ABS_SIZE(2),
920 beforeEditTextInfo.bbox.lty-GRID_ABS_SIZE(2),
921 beforeEditTextInfo.bbox.rbx+GRID_ABS_SIZE(2),
922 beforeEditTextInfo.bbox.rby+GRID_ABS_SIZE(2),
923 ltx, lty, rbx, rby);
924 } else {
925 RedrawAnArea(botObj, ltx, lty, rbx, rby);
926 }
927 firstMiniLine = lastMiniLine = NULL;
928 textCursorShown = FALSE;
929 curTextObj = NULL;
930 textCurIndex = 0;
931
932 SetEditTextArea(0, textCursorH, 0, 0);
933
934 PopCurFont();
935 ShowTextRelatedInfo();
936 if (editingText) {
937 editingText = FALSE;
938 }
939 textDrawn = FALSE;
940 justDrawnTextObj = NULL;
941 textHighlight = FALSE;
942 curTextIsNew = FALSE;
943
944 curStrBlock = endStrBlock = NULL;
945 textCurIndex = textEndIndex = INVALID;
946 textHighlight = FALSE;
947 }
948
949 static
RedrawAreasInCreateText(ltx1,lty1,rbx1,rby1,ltx2,lty2,rbx2,rby2)950 void RedrawAreasInCreateText(ltx1, lty1, rbx1, rby1, ltx2, lty2, rbx2, rby2)
951 int ltx1, lty1, rbx1, rby1, ltx2, lty2, rbx2, rby2;
952 {
953 struct BBRec bbox1, bbox2;
954
955 SetBBRec(&bbox1, ltx1, lty1, rbx1, rby1);
956 SetBBRec(&bbox2, ltx2, lty2, rbx2, rby2);
957 if (curTextObj != NULL) {
958 UnionRect(&bbox1, &curTextObj->bbox, &bbox1);
959 }
960 InflateBBox(&bbox2, -GRID_ABS_SIZE(2), -GRID_ABS_SIZE(2), &bbox2);
961 if (!BBoxIntersect(bbox1, bbox2)) {
962 RedrawAnArea(botObj, ltx2-GRID_ABS_SIZE(2), lty2-GRID_ABS_SIZE(2),
963 rbx2+GRID_ABS_SIZE(2), rby2+GRID_ABS_SIZE(2));
964 }
965 RedrawAreas(botObj, bbox1.ltx-GRID_ABS_SIZE(2), bbox1.lty-GRID_ABS_SIZE(2),
966 bbox1.rbx+GRID_ABS_SIZE(2), bbox1.rby+GRID_ABS_SIZE(2),
967 ltx2-GRID_ABS_SIZE(2), lty2-GRID_ABS_SIZE(2), rbx2+GRID_ABS_SIZE(2),
968 rby2+GRID_ABS_SIZE(2));
969 }
970
CreateTextObj(nDeactivateIM,nRedraw)971 int CreateTextObj(nDeactivateIM, nRedraw)
972 int nDeactivateIM, nRedraw;
973 /* returns TRUE if something got created */
974 /* returns FALSE otherwise */
975 {
976 struct TextRec *text_ptr=NULL;
977 struct AttrRec *attr_ptr=NULL;
978 MiniLinesInfo *minilines=NULL;
979 int num_lines=0, ltx=0, lty=0, rbx=0, rby=0, scr_ltx=0, scr_lty=0;
980 int saved_font=curFont, saved_style=curStyle, saved_sz_unit=curSzUnit;
981 int saved_just=textJust, saved_color=colorIndex;
982 int saved_underline_on=curUnderlineOn;
983 int saved_overline_on=curOverlineOn;
984
985 if (nDeactivateIM) {
986 if (canvasFontDoubleByte &&
987 tgIMDeactiveOnCreateText(mainDisplay, drawWindow)) {
988 if (tgIMHandleCreateText(mainDisplay, drawWindow)) {
989 }
990 }
991 }
992 if (!textCursorShown) return FALSE;
993
994 if (gstWBInfo.do_whiteboard) {
995 gstWBInfo.BlockRemoteCmdDepth--;
996 }
997 text_ptr = curTextObj->detail.t;
998 minilines = (&text_ptr->minilines);
999 num_lines = NumLinesInCurText();
1000
1001 if (editTextSize != 0) {
1002 RestoreEditTextSize(curTextObj, TRUE);
1003 RecalcTextMetrics(text_ptr, curTextObj->x, text_ptr->baseline_y);
1004 UpdateEditTextArea(minilines->w, minilines->h, minilines->min_lbearing,
1005 minilines->max_rextra);
1006 }
1007 if (curTextModified) {
1008 int retry=TRUE, shrunk=FALSE;
1009
1010 while (retry) {
1011 retry = FALSE;
1012 if (ShrinkMiniLines(&curTextObj->detail.t->minilines, &retry)) {
1013 shrunk = TRUE;
1014 }
1015 }
1016 if (shrunk) {
1017 curStrBlock = endStrBlock = NULL;
1018 textCurIndex = textEndIndex = INVALID;
1019 textHighlight = FALSE;
1020 UpdTextBBox(curTextObj);
1021 }
1022 }
1023 if (minilines->first == minilines->last && BlankMiniLine(minilines->first)) {
1024 /* no text entered or all text erased */
1025 CreateNoTextObj();
1026 UpdatePinnedMenu(MENU_EDIT);
1027
1028 if (saved_style != curStyle || saved_just != textJust ||
1029 saved_underline_on != curUnderlineOn ||
1030 saved_overline_on != curOverlineOn) {
1031 UpdatePinnedMenu(MENU_STYLE);
1032 }
1033 if (saved_font != curFont) UpdatePinnedMenu(MENU_FONT);
1034 if (saved_sz_unit != curSzUnit) UpdatePinnedMenu(MENU_SIZE);
1035 if (saved_color != colorIndex) UpdatePinnedMenu(MENU_COLOR);
1036
1037 if (gstWBInfo.do_whiteboard) {
1038 TryHandleWBInputData();
1039 SetCurChoice(DRAWTEXT);
1040 }
1041 curTextMovedAbsX = curTextMovedAbsY = 0;
1042 ClearCopyUTF8Info();
1043
1044 return FALSE;
1045 }
1046 if (curTextModified) {
1047 InvalidateTextCache(text_ptr);
1048 }
1049 text_ptr->lines = num_lines;
1050
1051 if (curTextObj->ctm == NULL) {
1052 curTextObj->x = textAbsX - tmpAdjAbsX - curTextMovedAbsX;
1053 text_ptr->baseline_y = textAbsBaselineY - tmpAdjAbsY - curTextMovedAbsY;
1054 curTextObj->y = text_ptr->baseline_y - minilines->first->asc;
1055 } else {
1056 int dx=0, dy=0;
1057
1058 if (beforeEditTextInfo.first_mini_line_asc != minilines->first->asc) {
1059 int anchor_x=0, anchor_y=0, x=0, y=0;
1060
1061 TransformPointThroughCTM(0, beforeEditTextInfo.first_mini_line_asc,
1062 curTextObj->ctm, &x, &y);
1063 anchor_x = curTextObj->x + x;
1064 anchor_y = curTextObj->y + y;
1065 TransformPointThroughCTM(0, minilines->first->asc,
1066 curTextObj->ctm, &x, &y);
1067 dx = anchor_x - (curTextObj->x + x);
1068 dy = anchor_y - (curTextObj->y + y);
1069 }
1070 curTextObj->x = textAbsX - tmpAdjAbsX - curTextMovedAbsX;
1071 curTextObj->y = textAbsY - tmpAdjAbsY - curTextMovedAbsY;
1072
1073 curTextObj->x += dx;
1074 curTextObj->y += dy;
1075
1076 curTextObj->x -= curTextObj->ctm->t[CTM_TX];
1077 curTextObj->y -= curTextObj->ctm->t[CTM_TY];
1078 }
1079 RecalcTextMetrics(text_ptr, curTextObj->x, text_ptr->baseline_y);
1080
1081 textJust = minilines->just;
1082
1083 SetTextOrigBBoxes(curTextObj, textJust, text_ptr->w, text_ptr->h,
1084 text_ptr->min_lbearing, text_ptr->max_rextra, ROTATE0);
1085 SetTextBBox(curTextObj, textJust, text_ptr->w, text_ptr->h,
1086 text_ptr->min_lbearing, text_ptr->max_rextra, ROTATE0);
1087 if (curTextObj->ctm != NULL) {
1088 GetTransformedOBBoxOffsetVs(curTextObj, curTextObj->rotated_obbox);
1089 }
1090 switch (textJust) {
1091 case JUST_L:
1092 scr_ltx = OFFSET_X(textAbsX-2);
1093 if (zoomedIn) {
1094 ltx = textAbsX-2-GRID_ABS_SIZE(2);
1095 rbx = textAbsX+textW+2+GRID_ABS_SIZE(2);
1096 } else {
1097 ltx = textAbsX-ABS_SIZE(2)-GRID_ABS_SIZE(2);
1098 rbx = textAbsX+ABS_SIZE(textW+2)+GRID_ABS_SIZE(2);
1099 }
1100 break;
1101 case JUST_C:
1102 scr_ltx = OFFSET_X(textAbsX)-textW/2-2;
1103 if (zoomedIn) {
1104 ltx = textAbsX-textW/2-2-GRID_ABS_SIZE(2);
1105 rbx = textAbsX+textW/2+2+GRID_ABS_SIZE(2);
1106 } else {
1107 ltx = textAbsX-ABS_SIZE(textW/2+2)-GRID_ABS_SIZE(2);
1108 rbx = textAbsX+ABS_SIZE(textW/2+2)+GRID_ABS_SIZE(2);
1109 }
1110 break;
1111 case JUST_R:
1112 scr_ltx = OFFSET_X(textAbsX)-textW-2;
1113 if (zoomedIn) {
1114 ltx = textAbsX-textW-2-GRID_ABS_SIZE(2);
1115 rbx = textAbsX+2+GRID_ABS_SIZE(2);
1116 } else {
1117 ltx = textAbsX-ABS_SIZE(textW+2)-GRID_ABS_SIZE(2);
1118 rbx = textAbsX+ABS_SIZE(2)+GRID_ABS_SIZE(2);
1119 }
1120 break;
1121 }
1122 scr_lty = OFFSET_Y(textAbsY);
1123 if (zoomedIn) {
1124 lty = textAbsY-2-GRID_ABS_SIZE(2);
1125 rby = textAbsY+textH+2+GRID_ABS_SIZE(2);
1126 } else {
1127 lty = textAbsY-ABS_SIZE(2)-GRID_ABS_SIZE(2);
1128 rby = textAbsY+ABS_SIZE(textH+2)+GRID_ABS_SIZE(2);
1129 }
1130
1131 if ((attr_ptr=text_ptr->attr) != NULL) {
1132 UpdateAttr(text_ptr, attr_ptr);
1133 textDrawn = FALSE;
1134 justDrawnTextObj = NULL;
1135 if (curTextModified && AutoCenterAttr(attr_ptr->owner)) {
1136 struct BBRec bbox;
1137
1138 CenterObjInOBBox(attr_ptr->obj, attr_ptr->owner->obbox, &bbox);
1139 if (bbox.ltx < ltx) ltx = bbox.ltx;
1140 if (bbox.lty < lty) lty = bbox.lty;
1141 if (bbox.rbx > rbx) rbx = bbox.rbx;
1142 if (bbox.rby > rby) rby = bbox.rby;
1143 }
1144 AdjObjBBox(attr_ptr->owner);
1145 if (outerSel != NULL) AdjAncestorsBBox();
1146
1147 if (curTextModified) {
1148 if (outerSel != NULL) {
1149 RecordReplaceAnObj(outerSel->obj);
1150 } else {
1151 RecordReplaceAnObj(attr_ptr->owner);
1152 }
1153 } else {
1154 AbortPrepareCmd(CMD_REPLACE);
1155 }
1156 } else {
1157 if (outerSel != NULL) {
1158 textDrawn = FALSE;
1159 justDrawnTextObj = NULL;
1160 AdjAncestorsBBox();
1161 } else {
1162 textDrawn = TRUE;
1163 justDrawnTextObj = curTextObj;
1164 }
1165 if (curTextIsNew) {
1166 AbortPrepareCmd(CMD_REPLACE);
1167 RecordNewObjCmd();
1168 } else if (curTextModified) {
1169 if (outerSel != NULL) {
1170 RecordReplaceAnObj(outerSel->obj);
1171 } else {
1172 RecordReplaceAnObj(curTextObj);
1173 }
1174 } else {
1175 AbortPrepareCmd(CMD_REPLACE);
1176 }
1177 }
1178 textCursorShown = FALSE;
1179 textCurIndex = 0;
1180
1181 GetCurTextBBoxes(&curTextOBBox, NULL);
1182 SetEditTextArea(curTextOBBox.rbx-curTextOBBox.ltx,
1183 curTextOBBox.rby-curTextOBBox.lty,
1184 text_ptr->minilines.min_lbearing, text_ptr->minilines.max_rextra);
1185
1186 if (editingText) {
1187 int x=0;
1188
1189 x = curTextBBox.ltx;
1190 XClearArea(mainDisplay, drawWindow,
1191 x-2-(curTextOutlineHalfW<<1),
1192 curTextBBox.lty-2-(curTextOutlineHalfW<<1),
1193 curTextBBox.rbx-x+5+(curTextOutlineHalfW<<2),
1194 curTextBBox.rby-curTextBBox.lty+5+(curTextOutlineHalfW<<2), FALSE);
1195
1196 if (ABS_X(x) < ltx) ltx = ABS_X(x);
1197 if (ABS_Y(textOrigY) < lty) lty = ABS_Y(textOrigY);
1198 x += textW-textAbsMinLBearing+textAbsMaxRExtra+1;
1199 if (ABS_X(x) > rbx) rbx = ABS_X(x);
1200 if (ABS_Y(textOrigY+textH+1) > rby) rby = ABS_Y(textOrigY+textH+1);
1201 if (curTextObj->ctm != NULL) {
1202 int i;
1203
1204 for (i=0; i < 4; i++) {
1205 int tmp_x=ABS_X(curTextObj->rotated_obbox[i].x);
1206 int tmp_y=ABS_Y(curTextObj->rotated_obbox[i].y);
1207
1208 if (tmp_x < ltx) ltx = tmp_x;
1209 if (tmp_y < lty) lty = tmp_y;
1210 if (tmp_x > rbx) rbx = tmp_x;
1211 if (tmp_y > rby) rby = tmp_y;
1212 }
1213 }
1214 if (nRedraw) {
1215 ltx -= (curTextOutlineHalfW<<1);
1216 lty -= (curTextOutlineHalfW<<1);
1217 rbx += (curTextOutlineHalfW<<1);
1218 rby += (curTextOutlineHalfW<<1);
1219 RedrawAreasInCreateText(beforeEditTextInfo.bbox.ltx,
1220 beforeEditTextInfo.bbox.lty, beforeEditTextInfo.bbox.rbx,
1221 beforeEditTextInfo.bbox.rby, ltx, lty, rbx, rby);
1222 }
1223 } else {
1224 int x=0;
1225
1226 switch (textJust) {
1227 case JUST_L: x = textOrigX+textAbsMinLBearing; break;
1228 case JUST_C: x = textOrigX-textW/2+textAbsMinLBearing; break;
1229 case JUST_R: x = textOrigX-textW+textAbsMinLBearing; break;
1230 }
1231 if (nRedraw) {
1232 ltx -= (curTextOutlineHalfW<<1);
1233 lty -= (curTextOutlineHalfW<<1);
1234 rbx += (curTextOutlineHalfW<<1);
1235 rby += (curTextOutlineHalfW<<1);
1236 RedrawAreasInCreateText(ltx, lty, rbx, rby, ABS_X(x-2),
1237 ABS_Y(textOrigY-2),
1238 ABS_X(x+textW-textAbsMinLBearing+textAbsMaxRExtra+3),
1239 ABS_Y(textOrigY+textH+3));
1240 }
1241 }
1242 textOrigX = textOrigY = textCurX = textCurY = ABS_SIZE(20);
1243
1244 SetEditTextArea(0, textCursorH, 0, 0);
1245
1246 textAbsX = textOrigX + drawOrigX;
1247 textAbsY = textOrigY + drawOrigY;
1248 curTextObj = NULL;
1249
1250 PopCurFont();
1251 ShowTextRelatedInfo();
1252 if (editingText) {
1253 editingText = FALSE;
1254 } else if (textRotation != 0) {
1255 int saved_rotation_increment=rotationIncrement;
1256 int saved_ltx=topObj->bbox.ltx, saved_lty=topObj->bbox.lty;
1257 int saved_rbx=topObj->bbox.rbx, saved_rby=topObj->bbox.rby;
1258
1259 SetRotatePivotByObject(topObj);
1260 rotationIncrement = textRotation;
1261 RotateObjClockWise(topObj);
1262 rotationIncrement = saved_rotation_increment;
1263 if (nRedraw) {
1264 RedrawAreasInCreateText(saved_ltx, saved_lty, saved_rbx, saved_rby,
1265 topObj->bbox.ltx, topObj->bbox.lty, topObj->bbox.rbx,
1266 topObj->bbox.rby);
1267 }
1268 }
1269 curTextIsNew = FALSE;
1270 SetTextHighlight();
1271 UpdatePinnedMenu(MENU_EDIT);
1272
1273 curStrBlock = endStrBlock = NULL;
1274 textCurIndex = textEndIndex = INVALID;
1275 textHighlight = FALSE;
1276
1277 if (saved_style != curStyle || saved_just != textJust ||
1278 saved_underline_on != curUnderlineOn ||
1279 saved_overline_on != curOverlineOn) {
1280 UpdatePinnedMenu(MENU_STYLE);
1281 }
1282 if (saved_font != curFont) UpdatePinnedMenu(MENU_FONT);
1283 if (saved_sz_unit != curSzUnit) UpdatePinnedMenu(MENU_SIZE);
1284 if (saved_color != colorIndex) UpdatePinnedMenu(MENU_COLOR);
1285
1286 if (gstWBInfo.do_whiteboard) {
1287 int saved_text_drawn=textDrawn;
1288
1289 textDrawn = FALSE;
1290 TryHandleWBInputData();
1291 if (justDrawnTextObj != NULL && !IsTopLevelObject(justDrawnTextObj)) {
1292 justDrawnTextObj = NULL;
1293 textDrawn = FALSE;
1294 } else {
1295 textDrawn = saved_text_drawn;
1296 }
1297 SetCurChoice(DRAWTEXT);
1298 }
1299 curTextMovedAbsX = curTextMovedAbsY = 0;
1300 ClearCopyUTF8Info();
1301
1302 if (rightMarginEnabled == TRUE) {
1303 if (!rightMarginActive) {
1304 rightMarginActive = TRUE;
1305 RedrawHRulerWindow();
1306 }
1307 }
1308 return TRUE;
1309 }
1310
1311 static
CanAdvanceRight(pStrBlock,nIndex)1312 int CanAdvanceRight(pStrBlock, nIndex)
1313 StrBlockInfo *pStrBlock;
1314 int nIndex;
1315 {
1316 if (nIndex != pStrBlock->seg->dyn_str.sz-1) {
1317 return TRUE;
1318 }
1319 if (pStrBlock->type == SB_SUPSUB_CENTER) {
1320 return FALSE;
1321 }
1322 for (pStrBlock=pStrBlock->next; pStrBlock != NULL;
1323 pStrBlock=pStrBlock->next) {
1324 switch (pStrBlock->type) {
1325 case SB_SIMPLE:
1326 if (*pStrBlock->seg->dyn_str.s != '\0') {
1327 return TRUE;
1328 }
1329 break;
1330 case SB_CHAR_SPACE: return TRUE;
1331
1332 case SB_SUPSUB_LEFT: return FALSE;
1333 case SB_SUPSUB_CENTER: return FALSE;
1334 case SB_SUPSUB_RIGHT: return FALSE;
1335 }
1336 }
1337 return FALSE;
1338 }
1339
1340 static
CanAdvanceLeft(pStrBlock,nIndex)1341 int CanAdvanceLeft(pStrBlock, nIndex)
1342 StrBlockInfo *pStrBlock;
1343 int nIndex;
1344 {
1345 if (nIndex != 0) {
1346 return TRUE;
1347 }
1348 if (pStrBlock->type == SB_SUPSUB_CENTER) {
1349 return FALSE;
1350 }
1351 for (pStrBlock=pStrBlock->prev; pStrBlock != NULL;
1352 pStrBlock=pStrBlock->prev) {
1353 switch (pStrBlock->type) {
1354 case SB_SIMPLE:
1355 if (*pStrBlock->seg->dyn_str.s != '\0') {
1356 return TRUE;
1357 }
1358 break;
1359 case SB_CHAR_SPACE: return TRUE;
1360
1361 case SB_SUPSUB_LEFT: return FALSE;
1362 case SB_SUPSUB_CENTER: return FALSE;
1363 case SB_SUPSUB_RIGHT: return FALSE;
1364 }
1365 }
1366 return FALSE;
1367 }
1368
AtBeginningOfInheritedAttrValue(obj_ptr,pStrBlock,nIndex)1369 int AtBeginningOfInheritedAttrValue(obj_ptr, pStrBlock, nIndex)
1370 struct ObjRec *obj_ptr;
1371 StrBlockInfo *pStrBlock;
1372 int nIndex;
1373 {
1374 if (obj_ptr->type == OBJ_TEXT) {
1375 struct TextRec *text_ptr=obj_ptr->detail.t;
1376 struct AttrRec *attr_ptr=text_ptr->attr;
1377
1378 if (attr_ptr != NULL && attr_ptr->inherited && attr_ptr->shown &&
1379 attr_ptr->nameshown) {
1380 if (pStrBlock != NULL && pStrBlock->prev == NULL &&
1381 pStrBlock->owner_mini_line == text_ptr->minilines.first) {
1382 if (nIndex <= attr_ptr->attr_name.sz-1) {
1383 return TRUE;
1384 }
1385 }
1386 }
1387 }
1388 return FALSE;
1389 }
1390
HighLightJustDrawnText()1391 void HighLightJustDrawnText()
1392 {
1393 if (justDrawnTextObj == NULL) return;
1394
1395 AddNewSelObj(justDrawnTextObj);
1396 UpdSelBBox();
1397 HighLightAnObj(justDrawnTextObj);
1398 justDupped = FALSE;
1399 }
1400
DelSelText()1401 void DelSelText()
1402 {
1403 if (textHighlight) {
1404 DeleteHighlightedText();
1405 EndChangeCurText(FALSE);
1406 }
1407 }
1408
1409 static
PrepareEditExistingText(obj_ptr,abs_x,abs_y,x_off,y_off)1410 int PrepareEditExistingText(obj_ptr, abs_x, abs_y, x_off, y_off)
1411 struct ObjRec *obj_ptr;
1412 int abs_x, abs_y, *x_off, *y_off;
1413 {
1414 struct TextRec *text_ptr=obj_ptr->detail.t;
1415 int orig_text_w=0, orig_text_h=0;
1416
1417 if (text_ptr->read_only) {
1418 MsgBox(TgLoadString(STID_READ_ONLY_TEXT_CANT_BE_EDITED), TOOL_NAME,
1419 INFO_MB);
1420 return FALSE;
1421 }
1422 curTextObj = obj_ptr;
1423 memset(&beforeEditTextInfo, 0, sizeof(struct tagBeforeEditTextInfo));
1424 memcpy(&beforeEditTextInfo.bbox, &obj_ptr->bbox, sizeof(struct BBRec));
1425 memcpy(&beforeEditTextInfo.obbox, &obj_ptr->obbox, sizeof(struct BBRec));
1426 beforeEditTextInfo.x = obj_ptr->x;
1427 beforeEditTextInfo.baseline_y = text_ptr->baseline_y;
1428 beforeEditTextInfo.first_mini_line_asc = text_ptr->minilines.first->asc;
1429 beforeEditTextInfo.obbox_w = orig_text_w =
1430 obj_ptr->obbox.rbx - obj_ptr->obbox.ltx;
1431 beforeEditTextInfo.obbox_h = orig_text_h =
1432 obj_ptr->obbox.rby - obj_ptr->obbox.lty;
1433
1434 PushCurFont();
1435 editingText = TRUE;
1436
1437 ObjFontInfoToCurFontInfo(text_ptr);
1438 penPat = text_ptr->pen;
1439 objFill = text_ptr->fill;
1440 transPat = obj_ptr->trans_pat;
1441
1442 SetEditTextArea(0, 0, 0, 0);
1443
1444 colorIndex = obj_ptr->color;
1445 ShowTextRelatedInfo();
1446 ResetOnCursorKey(FALSE);
1447
1448 textAbsX = obj_ptr->x;
1449 textAbsY = obj_ptr->y;
1450 textAbsBaselineY = text_ptr->baseline_y;
1451 if (obj_ptr->ctm != NULL) {
1452 textAbsX += obj_ptr->ctm->t[CTM_TX];
1453 textAbsY += obj_ptr->ctm->t[CTM_TY];
1454 textAbsBaselineY += obj_ptr->ctm->t[CTM_TY];
1455 }
1456 textOrigX = OFFSET_X(textAbsX);
1457 textOrigY = OFFSET_Y(textAbsY);
1458 textOrigBaselineY = textOrigY + text_ptr->baseline_y - obj_ptr->y;
1459
1460 if (editTextSize != 0) {
1461 if (RestoreEditTextSize(obj_ptr, FALSE)) {
1462 UpdTextBBox(obj_ptr);
1463 }
1464 }
1465 if (obj_ptr->ctm == NULL) {
1466 SetEditTextArea(obj_ptr->obbox.rbx-obj_ptr->obbox.ltx,
1467 obj_ptr->obbox.rby-obj_ptr->obbox.lty,
1468 text_ptr->min_lbearing, text_ptr->max_rextra);
1469 switch (textJust) {
1470 case JUST_L: tmpAdjAbsX = ((orig_text_w-ABS_SIZE(textW))>>1); break;
1471 case JUST_C: tmpAdjAbsX = 0; break;
1472 case JUST_R: tmpAdjAbsX = ((ABS_SIZE(textW)-orig_text_w)>>1); break;
1473 }
1474 tmpAdjAbsY = ((orig_text_h-ABS_SIZE(textH))>>1);
1475 } else {
1476 int abs_w=0, abs_h=0;
1477 int orig_2_xc=(beforeEditTextInfo.obbox.ltx+beforeEditTextInfo.obbox.rbx);
1478 int orig_2_yc=(beforeEditTextInfo.obbox.lty+beforeEditTextInfo.obbox.rby);
1479
1480 SetEditTextArea(obj_ptr->orig_obbox.rbx-obj_ptr->orig_obbox.ltx,
1481 obj_ptr->orig_obbox.rby-obj_ptr->orig_obbox.lty,
1482 text_ptr->min_lbearing, text_ptr->max_rextra);
1483 abs_w = ABS_SIZE(textW);
1484 abs_h = ABS_SIZE(textH);
1485
1486 switch (textJust) {
1487 case JUST_L: tmpAdjAbsX = ((orig_2_xc-abs_w)>>1)-textAbsX; break;
1488 case JUST_C: tmpAdjAbsX = ((orig_2_xc)>>1) - textAbsX; break;
1489 case JUST_R: tmpAdjAbsX = ((orig_2_xc+abs_w)>>1)-textAbsX; break;
1490 }
1491 tmpAdjAbsY = ((orig_2_yc - abs_h)>>1) - textAbsY;
1492 }
1493 textAbsX += tmpAdjAbsX;
1494 textAbsY += tmpAdjAbsY;
1495 textAbsBaselineY += tmpAdjAbsY;
1496 textOrigX = OFFSET_X(textAbsX);
1497 textOrigY = OFFSET_Y(textAbsY);
1498 textOrigBaselineY = textOrigY + text_ptr->baseline_y - obj_ptr->y;
1499
1500 if (obj_ptr->ctm == NULL) {
1501 abs_x += tmpAdjAbsX;
1502 abs_y += tmpAdjAbsY;
1503 } else {
1504 int x, y, dx=0;
1505
1506 ReverseTransformPointThroughCTM(abs_x-obj_ptr->x, abs_y-obj_ptr->y,
1507 obj_ptr->ctm, &x, &y);
1508 abs_x = obj_ptr->x + x;
1509 abs_y = obj_ptr->y + y;
1510
1511 switch (textJust) {
1512 case JUST_L: break;
1513 case JUST_C: dx = (textW>>1); break;
1514 case JUST_R: dx = textW; break;
1515 }
1516 abs_x += textAbsX - obj_ptr->orig_obbox.ltx - dx;
1517 abs_y += textAbsY - obj_ptr->orig_obbox.lty;
1518 }
1519 *x_off = OFFSET_X(abs_x);
1520 *y_off = OFFSET_Y(abs_y);
1521
1522 if (editTextSize != 0) {
1523 if (RestoreEditTextSize(curTextObj, TRUE)) {
1524 UpdTextBBox(curTextObj);
1525 }
1526 }
1527 if (outerSel != NULL) {
1528 PrepareToReplaceAnObj(outerSel->obj);
1529 } else if (text_ptr->attr == NULL) {
1530 PrepareToReplaceAnObj(obj_ptr);
1531 } else {
1532 PrepareToReplaceAnObj(text_ptr->attr->owner);
1533 }
1534 if (editTextSize != 0) {
1535 if (RestoreEditTextSize(curTextObj, FALSE)) {
1536 UpdTextBBox(curTextObj);
1537 }
1538 }
1539 SetEditTextArea(textW, textH, text_ptr->minilines.min_lbearing,
1540 text_ptr->minilines.max_rextra);
1541 UpdateCurTextBBoxes(TRUE);
1542
1543 if (gstWBInfo.do_whiteboard) {
1544 gstWBInfo.BlockRemoteCmdDepth++;
1545 }
1546 curTextMovedAbsX = curTextMovedAbsY = 0;
1547
1548 return TRUE;
1549 }
1550
1551 static
BeginAdvance(drag,dir,ppStrBlock,pnCurIndex)1552 int BeginAdvance(drag, dir, ppStrBlock, pnCurIndex)
1553 int drag, *pnCurIndex, dir;
1554 StrBlockInfo **ppStrBlock;
1555 {
1556 int position_end=FALSE;
1557
1558 if (drag) {
1559 if (textHighlight) {
1560 *ppStrBlock = endStrBlock;
1561 *pnCurIndex = textEndIndex;
1562 } else {
1563 *ppStrBlock = curStrBlock;
1564 *pnCurIndex = textCurIndex;
1565 }
1566 position_end = TRUE;
1567 } else {
1568 if (textHighlight) {
1569 textHighlight = FALSE;
1570 }
1571 if (dir == ADVANCE_RIGHT && endStrBlock != NULL) {
1572 *ppStrBlock = endStrBlock;
1573 *pnCurIndex = textEndIndex;
1574 position_end = TRUE;
1575 } else {
1576 *ppStrBlock = curStrBlock;
1577 *pnCurIndex = textCurIndex;
1578 }
1579 }
1580 return position_end;
1581 }
1582
1583 static
EndAdvance(position_end,pStrBlock,nCurIndex)1584 void EndAdvance(position_end, pStrBlock, nCurIndex)
1585 int position_end, nCurIndex;
1586 StrBlockInfo *pStrBlock;
1587 {
1588 if (position_end) {
1589 endStrBlock = pStrBlock;
1590 textEndIndex = nCurIndex;
1591 SetTextEndXY();
1592 } else {
1593 curStrBlock = pStrBlock;
1594 textCurIndex = nCurIndex;
1595 SetTextCurXY();
1596 }
1597 }
1598
1599 static
PartOfAWord(double_byte,ch)1600 int PartOfAWord(double_byte, ch)
1601 int double_byte;
1602 char ch;
1603 {
1604 if (double_byte) {
1605 return TRUE;
1606 }
1607 return (ch == '_' || (ch >= '0' && ch <= '9') ||
1608 (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'));
1609 }
1610
1611 #include "xbm/text_cur.xbm"
1612
1613 static
GetCursorPositionInCurText(x_off,y_off,use_abs,pn_abs_dx,pn_abs_baseline_dy,ppStrBlock,pnIndex)1614 int GetCursorPositionInCurText(x_off, y_off, use_abs, pn_abs_dx,
1615 pn_abs_baseline_dy, ppStrBlock, pnIndex)
1616 int x_off, y_off, use_abs, *pn_abs_dx, *pn_abs_baseline_dy, *pnIndex;
1617 StrBlockInfo **ppStrBlock;
1618 /*
1619 * returns -1 if caller needs to figure out where the beginning is
1620 * returns 0 if *pn_abs_dx and *pn_abs_baseline_dy are set
1621 * returns 1 if caller needs to figure out where the end is
1622 */
1623 {
1624 struct TextRec *text_ptr=curTextObj->detail.t;
1625 int x=0, y=0, orig_x=0, baseline_y=0, dx=0, dy=0, rc=TRUE;
1626
1627 if (use_abs) {
1628 x = ABS_X(x_off);
1629 y = ABS_Y(y_off);
1630 orig_x = textAbsX;
1631 baseline_y = textAbsBaselineY;
1632 } else {
1633 x = x_off;
1634 y = y_off;
1635 orig_x = textOrigX;
1636 baseline_y = textOrigBaselineY;
1637 }
1638 if (y < baseline_y-text_ptr->minilines.first->des-(text_cur_height>>1)) {
1639 if (text_cur_bits == NULL) { } /* no compiler warning */
1640 return INVALID;
1641 }
1642 PushCurFont();
1643 rc = GetCursorPositionInMiniLines(&text_ptr->minilines, x-orig_x,
1644 y-baseline_y, &dx, &dy, ppStrBlock, pnIndex);
1645 PopCurFont();
1646
1647 if (rc == 0) {
1648 *pn_abs_dx = dx;
1649 *pn_abs_baseline_dy = dy;
1650 }
1651 return rc;
1652 }
1653
1654 static
HandleClickOnCanvas(x_off,y_off)1655 void HandleClickOnCanvas(x_off, y_off)
1656 int x_off, y_off;
1657 {
1658 if (SzUnitToFontSize(curSzUnit) != canvasFontSize) {
1659 sprintf(gszMsgBox, TgLoadString(STID_TEXT_SZ_NOT_AVAIL_TRY_DIFF),
1660 SzUnitToFontSize(curSzUnit));
1661 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1662 } else {
1663 int grid_x=0, grid_y=0;
1664
1665 GridXY(x_off, y_off, &grid_x, &grid_y);
1666
1667 textOrigX = grid_x;
1668 textOrigBaselineY = grid_y;
1669 textOrigY = textOrigBaselineY-canvasFontAsc;
1670 textAbsMinLBearing = 0;
1671 textAbsMaxRExtra = 0;
1672 textAbsX = ABS_X(grid_x);
1673 textAbsBaselineY = ABS_Y(grid_y);
1674 textAbsY = textAbsBaselineY-canvasFontAsc;
1675 tmpAdjAbsX = tmpAdjAbsY = 0;
1676 curTextMovedAbsX = curTextMovedAbsY = 0;
1677 NewCurText();
1678 RedrawCurText();
1679 UpdateTextInfoChoices(TRUE);
1680 if (editTextSize != 0 && curStrBlock != NULL &&
1681 (curStrBlock->type == SB_SIMPLE ||
1682 curStrBlock->type == SB_SUPSUB_CENTER)) {
1683 CurFontMsg(FALSE, TRUE, curStrBlock->seg);
1684 } else {
1685 CurFontMsg(FALSE, TRUE, NULL);
1686 }
1687 if (gstWBInfo.do_whiteboard) {
1688 gstWBInfo.BlockRemoteCmdDepth++;
1689 }
1690 PrepareToReplaceAnObj(curTextObj);
1691 }
1692 }
1693
1694 static
AdjTextIndicesForInheritedAttr()1695 void AdjTextIndicesForInheritedAttr()
1696 {
1697 if (AtBeginningOfInheritedAttrValue(curTextObj, curStrBlock, textCurIndex)) {
1698 textCurIndex = curTextObj->detail.t->attr->attr_name.sz-1;
1699 SetTextCurXY();
1700 }
1701 if (AtBeginningOfInheritedAttrValue(curTextObj, endStrBlock, textEndIndex)) {
1702 textEndIndex = curTextObj->detail.t->attr->attr_name.sz-1;
1703 SetTextEndXY();
1704 }
1705 }
1706
1707 static
AdvanceForDoubleClickOnWord(double_byte)1708 void AdvanceForDoubleClickOnWord(double_byte)
1709 int double_byte;
1710 {
1711 char *psz=(curStrBlock->seg->dyn_str.s);
1712 int len=(curStrBlock->seg->dyn_str.sz-1);
1713 int step=(double_byte ? 2 : 1);
1714
1715 for ( ; textCurIndex > 0 &&
1716 PartOfAWord(double_byte, psz[textCurIndex-step]); textCurIndex-=step) {
1717 }
1718 for (endStrBlock=curStrBlock, textEndIndex=textCurIndex;
1719 textEndIndex < len &&
1720 PartOfAWord(double_byte, psz[textEndIndex]); textEndIndex+=step) {
1721 }
1722 }
1723
1724 static
AdvanceForDoubleClickOnSpaceChar()1725 void AdvanceForDoubleClickOnSpaceChar()
1726 {
1727 char *psz=(curStrBlock->seg->dyn_str.s);
1728 int len=(curStrBlock->seg->dyn_str.sz-1);
1729
1730 for ( ; textCurIndex > 0 && psz[textCurIndex-1] == ' '; textCurIndex--) {
1731 }
1732 for (endStrBlock=curStrBlock, textEndIndex=textCurIndex;
1733 textEndIndex < len && psz[textEndIndex] == ' '; textEndIndex++) {
1734 }
1735 }
1736
1737 static
AdvanceForDoubleClickOnText()1738 void AdvanceForDoubleClickOnText()
1739 {
1740 char cur_char=curStrBlock->seg->dyn_str.s[textCurIndex];
1741 int double_byte=curStrBlock->seg->double_byte;
1742 int select_word=PartOfAWord(double_byte, cur_char);
1743
1744 if (select_word) {
1745 AdvanceForDoubleClickOnWord(double_byte);
1746 } else {
1747 AdvanceForDoubleClickOnSpaceChar();
1748 }
1749 }
1750
1751 static
SetTextIndices(drag,x_off,y_off,pressed_in_same_text)1752 void SetTextIndices(drag, x_off, y_off, pressed_in_same_text)
1753 int drag, x_off, y_off, pressed_in_same_text;
1754 {
1755 MiniLinesInfo *minilines=(&curTextObj->detail.t->minilines);
1756 StrBlockInfo *pStrBlock=NULL;
1757 int index=INVALID, position_end=FALSE;
1758 int abs_dx=0, abs_baseline_dy=0;
1759
1760 position_end = BeginAdvance(drag, INVALID, &pStrBlock, &index);
1761
1762 switch (GetCursorPositionInCurText(x_off, y_off, !pressed_in_same_text,
1763 &abs_dx, &abs_baseline_dy, &pStrBlock, &index)) {
1764 case 0:
1765 if (position_end) {
1766 textEndX = textOrigX + abs_dx;
1767 textEndBaselineY = textOrigBaselineY + abs_baseline_dy;
1768 endStrBlock = pStrBlock;
1769 textEndIndex = index;
1770 } else {
1771 textCurX = textOrigX + abs_dx;
1772 textCurBaselineY = textOrigBaselineY + abs_baseline_dy;
1773 curStrBlock = pStrBlock;
1774 textCurIndex = index;
1775 }
1776 break;
1777 case 1:
1778 pStrBlock = minilines->last->last_block;
1779 index = pStrBlock->seg->dyn_str.sz-1;;
1780 if (position_end) {
1781 endStrBlock = pStrBlock;
1782 textEndIndex = index;
1783 } else {
1784 curStrBlock = pStrBlock;
1785 textCurIndex = index;
1786 }
1787 EndAdvance(position_end, pStrBlock, index);
1788 break;
1789 case (-1):
1790 pStrBlock = minilines->first->first_block;
1791 index = 0;
1792 if (position_end) {
1793 endStrBlock = pStrBlock;
1794 textEndIndex = index;
1795 } else {
1796 curStrBlock = pStrBlock;
1797 textCurIndex = index;
1798 }
1799 EndAdvance(position_end, pStrBlock, index);
1800 break;
1801 }
1802 AdjTextIndicesForInheritedAttr();
1803 }
1804
1805 static
AdvanceStrBlockToParentBlock(advance_left,position_end)1806 void AdvanceStrBlockToParentBlock(advance_left, position_end)
1807 int advance_left, position_end;
1808 {
1809 MiniLinesInfo *pOwnerMinilines=NULL;
1810
1811 if (advance_left) {
1812 if (position_end) {
1813 if (endStrBlock->type == SB_SUPSUB_CENTER) {
1814 endStrBlock = endStrBlock->prev;
1815 } else {
1816 pOwnerMinilines = endStrBlock->owner_mini_line->owner_minilines;
1817 endStrBlock = pOwnerMinilines->owner_block->prev;
1818 }
1819 textEndIndex = (endStrBlock->seg->dyn_str.sz-1);
1820 SetTextEndXY();
1821 } else {
1822 if (curStrBlock->type == SB_SUPSUB_CENTER) {
1823 curStrBlock = curStrBlock->prev;
1824 } else {
1825 pOwnerMinilines = curStrBlock->owner_mini_line->owner_minilines;
1826 curStrBlock = pOwnerMinilines->owner_block->prev;
1827 }
1828 textCurIndex = (curStrBlock->seg->dyn_str.sz-1);
1829 SetTextCurXY();
1830 }
1831 } else {
1832 if (position_end) {
1833 if (endStrBlock->type == SB_SUPSUB_CENTER) {
1834 endStrBlock = endStrBlock->next;
1835 } else {
1836 pOwnerMinilines = endStrBlock->owner_mini_line->owner_minilines;
1837 endStrBlock = pOwnerMinilines->owner_block->next;
1838 }
1839 textEndIndex = 0;
1840 SetTextEndXY();
1841 } else {
1842 if (curStrBlock->type == SB_SUPSUB_CENTER) {
1843 curStrBlock = curStrBlock->next;
1844 } else {
1845 pOwnerMinilines = curStrBlock->owner_mini_line->owner_minilines;
1846 curStrBlock = pOwnerMinilines->owner_block->next;
1847 }
1848 textCurIndex = 0;
1849 SetTextCurXY();
1850 }
1851 }
1852 }
1853
1854 static
FindStrBlockPosInMiniline(pMiniline,pStrBlockTarget,pnPos)1855 int FindStrBlockPosInMiniline(pMiniline, pStrBlockTarget, pnPos)
1856 MiniLineInfo *pMiniline;
1857 StrBlockInfo *pStrBlockTarget;
1858 int *pnPos;
1859 {
1860 StrBlockInfo *psbi=NULL;
1861
1862 for (psbi=pMiniline->first_block; psbi != NULL; psbi=psbi->next) {
1863 if (pnPos != NULL) (*pnPos)++;
1864 if (psbi->type == SB_SIMPLE) {
1865 if (psbi == pStrBlockTarget) {
1866 return TRUE;
1867 }
1868 }
1869 }
1870 return FALSE;
1871 }
1872
1873 static
FindStrBlockPosInMinilines(pMinilines,pStrBlockTarget)1874 int FindStrBlockPosInMinilines(pMinilines, pStrBlockTarget)
1875 MiniLinesInfo *pMinilines;
1876 StrBlockInfo *pStrBlockTarget;
1877 {
1878 MiniLineInfo *pMiniline=NULL;
1879 int pos=0;
1880
1881 for (pMiniline=pMinilines->first; pMiniline != NULL;
1882 pMiniline=pMiniline->next) {
1883 if (FindStrBlockPosInMiniline(pMiniline, pStrBlockTarget, &pos)) {
1884 return pos;
1885 }
1886 }
1887 return 0;
1888 }
1889
SwitchTextCurAndEndStrBlocks()1890 void SwitchTextCurAndEndStrBlocks()
1891 {
1892 StrBlockInfo *pStrBlock=curStrBlock;
1893 int index=textCurIndex;
1894
1895 curStrBlock = endStrBlock;
1896 textCurIndex = textEndIndex;
1897
1898 endStrBlock = pStrBlock;
1899 textEndIndex = index;
1900
1901 SetTextCurXY();
1902 SetTextEndXY();
1903 }
1904
FixHighlightedStrBlockDepths()1905 int FixHighlightedStrBlockDepths()
1906 {
1907 if (!textHighlight) {
1908 return 0;
1909 } else if (curStrBlock->depth == endStrBlock->depth) {
1910 if (curStrBlock->owner_mini_line->owner_minilines ==
1911 endStrBlock->owner_mini_line->owner_minilines) {
1912 if (curStrBlock == endStrBlock) {
1913 return textEndIndex - textCurIndex;
1914 } else {
1915 int cur_count = FindStrBlockPosInMinilines(
1916 curStrBlock->owner_mini_line->owner_minilines, curStrBlock);
1917 int end_count = FindStrBlockPosInMinilines(
1918 curStrBlock->owner_mini_line->owner_minilines, endStrBlock);
1919
1920 #ifdef _TGIF_DBG
1921 TgAssert(cur_count!=end_count,
1922 "cur_count==end_count in FixHighlightedStrBlockDepths()",
1923 NULL);
1924 #endif /* _TGIF_DBG */
1925 return end_count - cur_count;
1926 }
1927 }
1928 }
1929 if (curStrBlock->depth < endStrBlock->depth) {
1930 /* move endStrBlock */
1931 while (curStrBlock->depth < endStrBlock->depth) {
1932 if (curStrBlock->pre_order < endStrBlock->pre_order) {
1933 /* move endStrBlock to the right */
1934 AdvanceStrBlockToParentBlock(ADVANCE_RIGHT, POSITION_END);
1935 } else {
1936 /* move endStrBlock to the left */
1937 AdvanceStrBlockToParentBlock(ADVANCE_LEFT, POSITION_END);
1938 }
1939 }
1940 } else if (curStrBlock->depth > endStrBlock->depth) {
1941 /* move curStrBlock */
1942 while (curStrBlock->depth > endStrBlock->depth) {
1943 if (curStrBlock->pre_order < endStrBlock->pre_order) {
1944 /* move curStrBlock to the left */
1945 AdvanceStrBlockToParentBlock(ADVANCE_LEFT, POSITION_CUR);
1946 } else {
1947 /* move curStrBlock to the right */
1948 AdvanceStrBlockToParentBlock(ADVANCE_RIGHT, POSITION_CUR);
1949 }
1950 }
1951 }
1952 if (curStrBlock->depth == endStrBlock->depth) {
1953 while (curStrBlock->owner_mini_line->owner_minilines !=
1954 endStrBlock->owner_mini_line->owner_minilines) {
1955 if (curStrBlock->pre_order < endStrBlock->pre_order) {
1956 /* move curStrBlock to the left and endStrBlock to the right */
1957 AdvanceStrBlockToParentBlock(ADVANCE_LEFT, POSITION_CUR);
1958 AdvanceStrBlockToParentBlock(ADVANCE_RIGHT, POSITION_END);
1959 } else {
1960 /* move curStrBlock to the right and endStrBlock to the left */
1961 AdvanceStrBlockToParentBlock(ADVANCE_LEFT, POSITION_END);
1962 AdvanceStrBlockToParentBlock(ADVANCE_RIGHT, POSITION_CUR);
1963 }
1964 }
1965 } else {
1966 /* Should not get here! */
1967 }
1968 return 0;
1969 }
1970
1971 static Time lastClickTime=(Time)0;
1972 static int textJustClicked=FALSE;
1973
1974 static
DragButtonOnText()1975 void DragButtonOnText()
1976 {
1977 StrBlockInfo *pStrBlock=endStrBlock;
1978 int index=textEndIndex, done=FALSE;
1979
1980 if (!debugNoPointerGrab) {
1981 XGrabPointer(mainDisplay, drawWindow, FALSE,
1982 PointerMotionMask | ButtonReleaseMask,
1983 GrabModeAsync, GrabModeAsync, None, textCursor, CurrentTime);
1984 }
1985 SetTextHighlight();
1986 FixHighlightedStrBlockDepths();
1987 UpdatePinnedMenu(MENU_EDIT);
1988 RedrawCurText();
1989 UpdateHighLightedTextBBoxes(TRUE);
1990
1991 while (!done) {
1992 XEvent input;
1993
1994 XNextEvent(mainDisplay, &input);
1995
1996 if (input.type == Expose || input.type == VisibilityNotify) {
1997 ExposeEventHandler(&input, TRUE);
1998 } else if (input.type == ButtonRelease) {
1999 XUngrabPointer(mainDisplay, CurrentTime);
2000 done = TRUE;
2001 } else if (input.type == MotionNotify) {
2002 XEvent ev;
2003 int x_off=input.xmotion.x;
2004 int y_off=input.xmotion.y;
2005
2006 SetTextIndices(TRUE, x_off, y_off, TRUE);
2007
2008 if (pStrBlock != endStrBlock || index != textEndIndex) {
2009 SetTextHighlight();
2010 FixHighlightedStrBlockDepths();
2011 UpdatePinnedMenu(MENU_EDIT);
2012 UpdateHighLightedTextBBoxes(FALSE);
2013 RedrawCurText();
2014 UpdateHighLightedTextBBoxes(TRUE);
2015
2016 pStrBlock = endStrBlock;
2017 index = textEndIndex;
2018 }
2019 while (XCheckMaskEvent(mainDisplay,PointerMotionMask,&ev)) ;
2020 }
2021 }
2022 }
2023
2024 static
AdjustTextHighlight(drag,saved_text_highlight,update_highlighted_text_bboxes)2025 void AdjustTextHighlight(drag, saved_text_highlight,
2026 update_highlighted_text_bboxes)
2027 int drag, saved_text_highlight, update_highlighted_text_bboxes;
2028 {
2029 SetTextHighlight();
2030 if (!drag) {
2031 int rc=FixHighlightedStrBlockDepths();
2032
2033 if (rc < 0) {
2034 SwitchTextCurAndEndStrBlocks();
2035 }
2036 } else if (curStrBlock != NULL && endStrBlock != NULL &&
2037 curStrBlock->depth != endStrBlock->depth) {
2038 int rc=FixHighlightedStrBlockDepths();
2039
2040 if (rc < 0) {
2041 SwitchTextCurAndEndStrBlocks();
2042 }
2043 }
2044 UpdatePinnedMenu(MENU_EDIT);
2045 if (update_highlighted_text_bboxes) {
2046 UpdateHighLightedTextBBoxes(FALSE);
2047 }
2048 if (textCursorShown && !saved_text_highlight && !drag) {
2049 PutTextCursor();
2050 } else {
2051 RedrawCurText();
2052 }
2053 ScrollTo(textCurX, textCurBaselineY);
2054 }
2055
2056 static
HandleClickOnText(drag,from_cursor_keys,x_off,y_off,pressed_in_same_text,obj_ptr,double_clicked,saved_text_highlight,skip_post_processing,click_time)2057 void HandleClickOnText(drag, from_cursor_keys, x_off, y_off,
2058 pressed_in_same_text, obj_ptr, double_clicked, saved_text_highlight,
2059 skip_post_processing, click_time)
2060 int drag, from_cursor_keys, x_off, y_off, pressed_in_same_text;
2061 int double_clicked, saved_text_highlight;
2062 struct ObjRec *obj_ptr;
2063 Time click_time;
2064 {
2065 SetTextIndices(drag, x_off, y_off, pressed_in_same_text);
2066
2067 textCursorShown = TRUE;
2068
2069 if (gnInputMethod != TGIM_NONE) {
2070 if (!tgIMHandleNewCurText(mainDisplay, drawWindow)) {
2071 }
2072 }
2073 if (double_clicked) {
2074 ResetOnCursorKey(FALSE);
2075 SetTextHighlight();
2076 UpdatePinnedMenu(MENU_EDIT);
2077
2078 AdvanceForDoubleClickOnText();
2079
2080 SetTextCurXY();
2081 SetTextEndXY();
2082 textJustClicked = FALSE;
2083 } else if (!from_cursor_keys) {
2084 textJustClicked = TRUE;
2085 lastClickTime = click_time;
2086
2087 DragButtonOnText();
2088 }
2089 if (!skip_post_processing) {
2090 AdjustTextHighlight(drag, saved_text_highlight,
2091 from_cursor_keys || double_clicked);
2092 }
2093 }
2094
2095 static
HandleButton(Button_Ev)2096 void HandleButton(Button_Ev)
2097 XButtonEvent *Button_Ev;
2098 {
2099 int x_off=0, y_off=0, update_highlighted_text_bboxes=FALSE;
2100
2101 if (!textCursorShown) {
2102 ClearCopyUTF8Info();
2103 }
2104 escPressed = FALSE;
2105 if (Button_Ev->button == Button1 &&
2106 !(Button_Ev->state & (ShiftMask|ControlMask))) {
2107 struct ObjRec *obj_ptr=NULL;
2108 int pressed_in_same_text=FALSE, x=0, abs_x=0, abs_y=0;
2109
2110 x_off = Button_Ev->x; abs_x = ABS_X(x_off);
2111 y_off = Button_Ev->y; abs_y = ABS_Y(y_off);
2112
2113 if (textCursorShown) {
2114 switch (curTextObj->detail.t->minilines.just) {
2115 case JUST_L: x = textOrigX-2; break;
2116 case JUST_C: x = textOrigX-textW/2-2; break;
2117 case JUST_R: x = textOrigX-textW-2; break;
2118 }
2119 if (x_off >= x && x_off <= x+textW+4 &&
2120 y_off >= textOrigY-2 && y_off <= textOrigY+textH+2) {
2121 pressed_in_same_text = TRUE;
2122 if (textHighlight) {
2123 UpdateHighLightedTextBBoxes(TRUE);
2124 update_highlighted_text_bboxes = TRUE;
2125 } else {
2126 EraseTextCursor();
2127 }
2128 } else {
2129 CreateTextObj(TRUE, TRUE); /* end editing on the old text */
2130 curTextModified = FALSE;
2131 }
2132 } else {
2133 editingText = FALSE;
2134 curTextModified = FALSE;
2135 }
2136 ResetOnCursorKey(FALSE);
2137
2138 if (!pressed_in_same_text &&
2139 (obj_ptr=FindTextObj(x_off, y_off, NULL)) == NULL) {
2140 /* cursor not within any existing text object */
2141 HandleClickOnCanvas(x_off, y_off);
2142 } else {
2143 /* cursor inside an existing text object */
2144 Time click_time=Button_Ev->time;
2145 int double_clicked=FALSE;
2146
2147 double_clicked = (pressed_in_same_text && textJustClicked &&
2148 (click_time-lastClickTime) < doubleClickInterval);
2149 if (pressed_in_same_text) {
2150 obj_ptr = curTextObj;
2151 if (textJustClicked && (click_time-lastClickTime) <
2152 doubleClickInterval) {
2153 double_clicked = TRUE;
2154 }
2155 } else {
2156 if (!PrepareEditExistingText(obj_ptr, abs_x, abs_y,
2157 &x_off, &y_off)) {
2158 return;
2159 }
2160 }
2161 if (!update_highlighted_text_bboxes && curStrBlock != NULL) {
2162 UpdateHighLightedTextBBoxes(TRUE);
2163 }
2164 HandleClickOnText(FALSE, FALSE, x_off, y_off, pressed_in_same_text,
2165 obj_ptr, double_clicked, TRUE, FALSE, click_time);
2166 UpdateTextInfoChoices(TRUE);
2167 }
2168 } else if (Button_Ev->button == Button1 &&
2169 (Button_Ev->state & (ShiftMask|ControlMask))) {
2170 if (!textCursorShown) return;
2171
2172 x_off = Button_Ev->x;
2173 y_off = Button_Ev->y;
2174
2175 if (curStrBlock != NULL) UpdateHighLightedTextBBoxes(TRUE);
2176 HandleClickOnText(TRUE, FALSE, x_off, y_off, TRUE, curTextObj, FALSE,
2177 TRUE, FALSE, (Time)0);
2178 UpdateTextInfoChoices(FALSE);
2179 }
2180 }
2181
2182 static
AdvanceRight(drag)2183 void AdvanceRight(drag)
2184 int drag;
2185 {
2186 StrBlockInfo *pStrBlock=NULL;
2187 int index=INVALID, position_end=FALSE;
2188 int done=FALSE, something_skipped=FALSE;
2189
2190 position_end = BeginAdvance(drag, ADVANCE_RIGHT, &pStrBlock, &index);
2191
2192 while (!done) {
2193 switch (pStrBlock->type) {
2194 case SB_SIMPLE:
2195 case SB_SUPSUB_CENTER:
2196 if (something_skipped) {
2197 done = TRUE;
2198 } else if (index < pStrBlock->seg->dyn_str.sz-1) {
2199 if (pStrBlock->seg->double_byte) {
2200 index += 2;
2201 } else {
2202 index++;
2203 }
2204 done = TRUE;
2205 }
2206 break;
2207 default: something_skipped = TRUE; break;
2208 }
2209 if (done) {
2210 EndAdvance(position_end, pStrBlock, index);
2211 } else if (pStrBlock->next == NULL) {
2212 MiniLineInfo *owner_mini_line=pStrBlock->owner_mini_line;
2213 MiniLinesInfo *owner_minilines=owner_mini_line->owner_minilines;
2214
2215 if (owner_mini_line->next == NULL &&
2216 owner_minilines->owner_block != NULL &&
2217 owner_minilines->owner_block->next != NULL) {
2218 pStrBlock = owner_minilines->owner_block->next;
2219 something_skipped = TRUE;
2220 } else {
2221 done = TRUE;
2222 }
2223 } else {
2224 if (pStrBlock->type == SB_SUPSUB_CENTER) {
2225 pStrBlock = pStrBlock->next;
2226 something_skipped = TRUE;
2227 } else {
2228 pStrBlock = pStrBlock->next;
2229 if (pStrBlock->type == SB_SUPSUB_CENTER) {
2230 pStrBlock = pStrBlock->next;
2231 something_skipped = TRUE;
2232 }
2233 }
2234 }
2235 if (!done) {
2236 if (pStrBlock->type == SB_SIMPLE) {
2237 index = 0;
2238 }
2239 }
2240 }
2241 }
2242
2243 static
AdvanceLeft(drag)2244 void AdvanceLeft(drag)
2245 int drag;
2246 {
2247 StrBlockInfo *pStrBlock=NULL;
2248 int index=INVALID, position_end=FALSE;
2249 int done=FALSE, something_skipped=FALSE;
2250
2251 position_end = BeginAdvance(drag, ADVANCE_LEFT, &pStrBlock, &index);
2252
2253 while (!done) {
2254 switch (pStrBlock->type) {
2255 case SB_SIMPLE:
2256 case SB_SUPSUB_CENTER:
2257 if (something_skipped) {
2258 done = TRUE;
2259 } else if (index != 0) {
2260 if (pStrBlock->seg->double_byte) {
2261 index -= 2;
2262 } else {
2263 index--;
2264 }
2265 done = TRUE;
2266 }
2267 break;
2268 default: something_skipped = TRUE; break;
2269 }
2270 if (done) {
2271 EndAdvance(position_end, pStrBlock, index);
2272 } else if (pStrBlock->prev == NULL) {
2273 MiniLineInfo *owner_mini_line=pStrBlock->owner_mini_line;
2274 MiniLinesInfo *owner_minilines=owner_mini_line->owner_minilines;
2275
2276 if (owner_mini_line->prev == NULL &&
2277 owner_minilines->owner_block != NULL) {
2278 pStrBlock = owner_minilines->owner_block->prev;
2279 something_skipped = TRUE;
2280 } else {
2281 done = TRUE;
2282 }
2283 } else {
2284 if (pStrBlock->type == SB_SUPSUB_CENTER) {
2285 pStrBlock = pStrBlock->prev;
2286 something_skipped = TRUE;
2287 } else {
2288 pStrBlock = pStrBlock->prev;
2289 if (pStrBlock->type == SB_SUPSUB_CENTER) {
2290 pStrBlock = pStrBlock->prev;
2291 something_skipped = TRUE;
2292 }
2293 }
2294 }
2295 if (!done) {
2296 if (pStrBlock->type == SB_SIMPLE) {
2297 index = pStrBlock->seg->dyn_str.sz-1;
2298 }
2299 }
2300 }
2301 AdjTextIndicesForInheritedAttr();
2302 }
2303
2304 static
InsertCRLFIntoCurText()2305 void InsertCRLFIntoCurText()
2306 {
2307 MiniLineInfo *pNewMiniLine=NewMiniLine();
2308 MiniLineInfo *owner_mini_line=curStrBlock->owner_mini_line;
2309 MiniLinesInfo *minilines=owner_mini_line->owner_minilines;
2310 StrBlockInfo *pStrBlock=NULL, *pRightStrBlock=NULL;
2311 char *psz=UtilStrDup(curStrBlock->seg->dyn_str.s), saved_ch='\0';
2312
2313 if (psz == NULL) FailAllocMessage();
2314
2315 DupStrBlock(curStrBlock, owner_mini_line, &pRightStrBlock,
2316 &pRightStrBlock);
2317 saved_ch = psz[textCurIndex];
2318 psz[textCurIndex] = '\0';
2319 DynStrSet(&curStrBlock->seg->dyn_str, psz);
2320 psz[textCurIndex] = saved_ch;
2321 DynStrSet(&pRightStrBlock->seg->dyn_str, &psz[textCurIndex]);
2322 UtilFree(psz);
2323
2324 pRightStrBlock->next = curStrBlock->next;
2325 if (curStrBlock->next != NULL) {
2326 curStrBlock->next->prev = pRightStrBlock;
2327 }
2328 curStrBlock->next = NULL;
2329 owner_mini_line->last_block = curStrBlock;
2330 pNewMiniLine->owner_minilines = minilines;
2331
2332 InsertMiniLine(owner_mini_line, owner_mini_line->next, pNewMiniLine,
2333 &minilines->first, &minilines->last);
2334
2335 pNewMiniLine->first_block = pNewMiniLine->last_block = pRightStrBlock;
2336 pRightStrBlock->prev = NULL;
2337 for (pStrBlock=pRightStrBlock; pStrBlock != NULL;
2338 pStrBlock=pStrBlock->next) {
2339 pNewMiniLine->last_block = pStrBlock;
2340 pStrBlock->owner_mini_line = pNewMiniLine;
2341 }
2342 curStrBlock = pRightStrBlock;
2343 textCurIndex = 0;
2344 ResetOnCursorKey(FALSE);
2345 SetTextHighlight();
2346 UpdatePinnedMenu(MENU_EDIT);
2347 }
2348
2349 static
DoMoveTextCursorToNextMiniLine()2350 void DoMoveTextCursorToNextMiniLine()
2351 {
2352 int saved_text_highlight=textHighlight;
2353 MiniLineInfo *owner_mini_line=curStrBlock->owner_mini_line;
2354 MiniLinesInfo *owner_minilines=owner_mini_line->owner_minilines;
2355
2356 if (textCursorShown && !saved_text_highlight) {
2357 EraseTextCursor();
2358 }
2359 UpdateHighLightedTextBBoxes(TRUE);
2360
2361 if (owner_mini_line->next == NULL) {
2362 curStrBlock = owner_minilines->first->first_block;
2363 } else {
2364 curStrBlock = owner_mini_line->next->first_block;
2365 }
2366 textCurIndex = 0;
2367
2368 ResetOnCursorKey(FALSE);
2369 SetTextCurXY();
2370 SetTextHighlight();
2371 UpdatePinnedMenu(MENU_EDIT);
2372 if (textCursorShown && !saved_text_highlight) {
2373 PutTextCursor();
2374 } else {
2375 RedrawCurText();
2376 }
2377 MarkRulers(textCurX, textCurY);
2378 ScrollTo(textCurX, textCurBaselineY);
2379 UpdateTextInfoChoices(FALSE);
2380 }
2381
2382 static
HandleCRLF(key_ev)2383 void HandleCRLF(key_ev)
2384 XKeyEvent *key_ev;
2385 {
2386 int cycle=(key_ev != NULL && (key_ev->state & ControlMask) != 0);
2387
2388 escPressed = FALSE;
2389
2390 if (cycle) {
2391 if (curStrBlock->type != SB_SUPSUB_CENTER) {
2392 DoMoveTextCursorToNextMiniLine();
2393 }
2394 return;
2395 }
2396 if (curStrBlock->type == SB_SUPSUB_CENTER) {
2397 return;
2398 }
2399 curTextModified = TRUE;
2400 if (textHighlight) {
2401 DeleteHighlightedText();
2402 EndChangeCurText(FALSE);
2403 }
2404 InsertCRLFIntoCurText();
2405 EndChangeCurText(TRUE);
2406
2407 if (!gnDontRedrawDuringPaste) {
2408 ScrollTo(textCurX, textCurBaselineY);
2409 } else {
2410 gnPastingLineNum++;
2411 sprintf(gszMsgBox, TgLoadCachedString(CSTID_PASTING_LINE_NUM_DOTS),
2412 gnPastingLineNum+1);
2413 SetStringStatus(gszMsgBox);
2414 }
2415 }
2416
2417 static
HandleBS(key_ev,buf,key_sym,pn_has_char)2418 void HandleBS(key_ev, buf, key_sym, pn_has_char)
2419 XKeyEvent *key_ev;
2420 char *buf;
2421 KeySym key_sym;
2422 int *pn_has_char;
2423 {
2424 struct AttrRec *attr_ptr=NULL;
2425 int merged_lines=FALSE;
2426 int nDeleteNextChar=(deleteNextCharWithDelKey &&
2427 CharIsDEL(key_ev, buf, key_sym, pn_has_char)) ||
2428 (!deleteNextCharWithDelKey && (key_ev != NULL &&
2429 (key_ev->state & (ControlMask | ShiftMask)) &&
2430 !((key_ev->state & ControlMask) && (key_sym == XK_h))));
2431
2432 escPressed = FALSE;
2433
2434 if (textHighlight) {
2435 DeleteHighlightedText();
2436 EndChangeCurText(FALSE);
2437 return;
2438 }
2439 attr_ptr = curTextObj->detail.t->attr;
2440 if (nDeleteNextChar) {
2441 if (CanAdvanceRight(curStrBlock, textCurIndex)) {
2442 AdvanceRight(TRUE);
2443 } else if (curStrBlock->next == NULL) {
2444 MiniLineInfo *pNextMiniLine=curStrBlock->owner_mini_line->next;
2445
2446 if (pNextMiniLine == NULL) {
2447 return;
2448 }
2449 endStrBlock = pNextMiniLine->first_block;
2450 textEndIndex = 0;
2451 merged_lines = TRUE;
2452 } else {
2453 return;
2454 }
2455 SetTextHighlight();
2456 DeleteHighlightedText();
2457 if (merged_lines) {
2458 ResetDirtyBBoxInfo();
2459 }
2460 EndChangeCurText(merged_lines);
2461 UpdatePinnedMenu(MENU_EDIT);
2462 return;
2463 }
2464 if (AtBeginningOfInheritedAttrValue(curTextObj, curStrBlock, textCurIndex)) {
2465 return;
2466 }
2467 curTextModified = TRUE;
2468 if (textCurIndex != 0) {
2469 StrSegInfo *pStrSeg=curStrBlock->seg;
2470 int i=0, step=(pStrSeg->double_byte ? 2 : 1);
2471 char *psz=curStrBlock->seg->dyn_str.s;
2472
2473 for (i=textCurIndex; i < pStrSeg->dyn_str.sz; i+=step) {
2474 if (step == 1) {
2475 psz[i-1] = psz[i];
2476 } else {
2477 psz[i-2] = psz[i];
2478 psz[i-1] = psz[i+1];
2479 }
2480 }
2481 textCurIndex -= step;
2482 pStrSeg->dyn_str.sz -= step;
2483 } else {
2484 if (CanAdvanceLeft(curStrBlock, textCurIndex)) {
2485 AdvanceLeft(TRUE);
2486 } else if (curStrBlock->prev == NULL) {
2487 MiniLineInfo *pNextMiniLine=curStrBlock->owner_mini_line->prev;
2488
2489 if (pNextMiniLine == NULL) {
2490 return;
2491 }
2492 endStrBlock = pNextMiniLine->last_block;
2493 textEndIndex = endStrBlock->seg->dyn_str.sz-1;
2494 merged_lines = TRUE;
2495 } else {
2496 return;
2497 }
2498 SetTextHighlight();
2499 DeleteHighlightedText();
2500 UpdatePinnedMenu(MENU_EDIT);
2501 }
2502 if (merged_lines) {
2503 ResetDirtyBBoxInfo();
2504 }
2505 EndChangeCurText(merged_lines);
2506 }
2507
2508 static
InsertSingleByteCharIntoCurText(Str)2509 int InsertSingleByteCharIntoCurText(Str)
2510 char *Str;
2511 {
2512 MiniLineInfo *owner_mini_line=curStrBlock->owner_mini_line;
2513 StrBlockInfo *pLeftStrBlock=NULL;
2514
2515 DupStrBlock(curStrBlock, owner_mini_line, &pLeftStrBlock, &pLeftStrBlock);
2516 pLeftStrBlock->seg->double_byte = FALSE;
2517 pLeftStrBlock->seg->font = defaultSingleByteFont;
2518 DynStrSet(&pLeftStrBlock->seg->dyn_str, Str);
2519 pLeftStrBlock->clean = FALSE;
2520
2521 if (textCurIndex == 0 && curStrBlock->prev != NULL &&
2522 curStrBlock->prev->type == SB_SIMPLE &&
2523 !curStrBlock->prev->seg->double_byte &&
2524 StrBlocksHasSameProperties(pLeftStrBlock, curStrBlock->prev)) {
2525 /* just add the current char to curStrBlock->prev */
2526 char *psz=(char*)malloc(curStrBlock->prev->seg->dyn_str.sz+1);
2527
2528 if (psz == NULL) FailAllocMessage();
2529 sprintf(psz, "%s%s", curStrBlock->prev->seg->dyn_str.s, Str);
2530 DynStrSet(&curStrBlock->prev->seg->dyn_str, psz);
2531 curStrBlock->prev->clean = FALSE;
2532
2533 UtilFree(psz);
2534 FreeStrBlock(pLeftStrBlock);
2535 return TRUE;
2536 }
2537 if (textCurIndex != 0) {
2538 StrBlockInfo *pDupStrBlock=NULL;
2539
2540 DupStrBlock(curStrBlock, owner_mini_line, &pDupStrBlock, &pDupStrBlock);
2541 pDupStrBlock->seg->dyn_str.s[textCurIndex] = '\0';
2542 DynStrSet(&pDupStrBlock->seg->dyn_str, pDupStrBlock->seg->dyn_str.s);
2543 DynStrSet(&curStrBlock->seg->dyn_str,
2544 &curStrBlock->seg->dyn_str.s[textCurIndex]);
2545 pDupStrBlock->prev = curStrBlock->prev;
2546 if (curStrBlock->prev == NULL) {
2547 owner_mini_line->first_block = pDupStrBlock;
2548 } else {
2549 curStrBlock->prev->next = pDupStrBlock;
2550 }
2551 pDupStrBlock->next = curStrBlock;
2552 curStrBlock->prev = pDupStrBlock;
2553
2554 curStrBlock->clean = pDupStrBlock->clean = FALSE;
2555
2556 textCurIndex = 0;
2557 }
2558 pLeftStrBlock->prev = curStrBlock->prev;
2559 if (curStrBlock->prev == NULL) {
2560 owner_mini_line->first_block = pLeftStrBlock;
2561 } else {
2562 curStrBlock->prev->next = pLeftStrBlock;
2563 }
2564 pLeftStrBlock->next = curStrBlock;
2565 curStrBlock->prev = pLeftStrBlock;
2566
2567 return TRUE;
2568 }
2569
2570 static
InsertCharIntoCurText(Str,double_byte)2571 int InsertCharIntoCurText(Str, double_byte)
2572 char *Str;
2573 int double_byte;
2574 {
2575 if (curStrBlock->seg->double_byte && !double_byte) {
2576 if (curStrBlock->type == SB_SUPSUB_CENTER) {
2577 MsgBox(TgLoadString(STID_CANT_INS_NON_DB_CH_AT_CUR_REM), TOOL_NAME,
2578 INFO_MB);
2579 return FALSE;
2580 } else {
2581 InsertSingleByteCharIntoCurText(Str);
2582 }
2583 } else {
2584 char *buf=NULL;
2585 int cur_index_is_last=(textCurIndex==curStrBlock->seg->dyn_str.sz-1);
2586
2587 if (lengthLimit256InInsertChar &&
2588 curStrBlock->seg->dyn_str.sz-1+(double_byte ? 2 : 1) >= MAXSTRING) {
2589 sprintf(gszMsgBox, TgLoadString(STID_STR_EXCEEDS_NUM_CH_IGNORED),
2590 MAXSTRING);
2591 Msg(gszMsgBox);
2592 return FALSE;
2593 }
2594 buf = (char*)malloc((curStrBlock->seg->dyn_str.sz+7)*sizeof(char));
2595 if (buf == NULL) FailAllocMessage();
2596
2597 if (double_byte) {
2598 char tmp_s[3];
2599
2600 tmp_s[0] = curStrBlock->seg->dyn_str.s[textCurIndex];
2601 curStrBlock->seg->dyn_str.s[textCurIndex] = '\0';
2602 if (tmp_s[0] != '\0') {
2603 tmp_s[1] = curStrBlock->seg->dyn_str.s[textCurIndex+1];
2604 curStrBlock->seg->dyn_str.s[textCurIndex+1] = '\0';
2605 sprintf(buf, "%s%c%c%c%c%s", curStrBlock->seg->dyn_str.s,
2606 Str[0], Str[1], tmp_s[0], tmp_s[1],
2607 (cur_index_is_last ? "" :
2608 (&curStrBlock->seg->dyn_str.s[textCurIndex+2])));
2609 } else {
2610 sprintf(buf, "%s%c%c", curStrBlock->seg->dyn_str.s, Str[0], Str[1]);
2611 }
2612 textCurIndex += 2;
2613 } else {
2614 char tmp_char=curStrBlock->seg->dyn_str.s[textCurIndex];
2615
2616 curStrBlock->seg->dyn_str.s[textCurIndex] = '\0';
2617 sprintf(buf, "%s%c%c%s", curStrBlock->seg->dyn_str.s, *Str, tmp_char,
2618 (cur_index_is_last ? "" :
2619 (&curStrBlock->seg->dyn_str.s[textCurIndex+1])));
2620 textCurIndex++;
2621 }
2622 DynStrSet(&curStrBlock->seg->dyn_str, buf);
2623 curStrBlock->clean = FALSE;
2624 free(buf);
2625 }
2626 EndChangeCurText(FALSE);
2627
2628 return TRUE;
2629 }
2630
2631 static
SwitchToSingleOrDoubleByteFont(pStrSeg)2632 int SwitchToSingleOrDoubleByteFont(pStrSeg)
2633 StrSegInfo *pStrSeg;
2634 {
2635 int saved_sz_unit=curSzUnit, saved_font=curFont, saved_style=curStyle;
2636
2637 if (!(curChoice == DRAWTEXT && textCursorShown)) {
2638 TieLooseEnds();
2639 }
2640 curFont = pStrSeg->font;
2641 curStyle = pStrSeg->style;
2642 curSzUnit = pStrSeg->sz_unit;
2643 if (curChoice == DRAWTEXT && textCursorShown && editTextSize != 0) {
2644 curSzUnit = GetCurSzUnit();
2645 }
2646 allowFontFaceSubstitution = FALSE;
2647 SetCanvasFont();
2648 allowFontFaceSubstitution = TRUE;
2649 if (canvasFontSize == INVALID) {
2650 char buf[MAXSTRING];
2651
2652 GetCurFontMsg(buf, NULL);
2653 curFont = saved_font;
2654 curStyle = saved_style;
2655 curSzUnit = saved_sz_unit;
2656 SetCanvasFont();
2657 sprintf(gszMsgBox, TgLoadString(STID_FONT_NOT_AVAILABLE), buf);
2658 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2659 } else if (SzUnitToFontSize(curSzUnit) != canvasFontSize) {
2660 if (showFontSizeInPoints) {
2661 sprintf(gszMsgBox, TgLoadString(STID_CANT_CHANGE_SIZEPT_TO_USE_ALT),
2662 SzUnitToPointSize(curSzUnit),
2663 SzUnitToPointSize(FontSizeToSzUnit(canvasFontSize)));
2664 } else {
2665 sprintf(gszMsgBox, TgLoadString(STID_CANT_CHANGE_SIZE_TO_USE_ALT),
2666 SzUnitToFontSize(curSzUnit), canvasFontSize);
2667 }
2668 curSzUnit = FontSizeToSzUnit(canvasFontSize);
2669 if (curChoice == DRAWTEXT && textCursorShown && editTextSize != 0) {
2670 PutCurSzUnit(curSzUnit);
2671 }
2672 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2673 } else if (curChoice == DRAWTEXT && textCursorShown &&
2674 editTextSize != 0) {
2675 PutCurSzUnit(curSzUnit);
2676 }
2677 if (curChoice == DRAWTEXT && textCursorShown) {
2678 ChangeEditTextProperty(PROP_MASK_TEXT_FONT, pStrSeg->font);
2679 ChangeEditTextProperty(PROP_MASK_TEXT_STYLE, pStrSeg->style);
2680 ChangeEditTextProperty(PROP_MASK_TEXT_SZ_UNIT, pStrSeg->sz_unit);
2681
2682 curTextModified = TRUE;
2683 UpdCurTextBBox();
2684 RedrawCurText();
2685 SetFileModified(TRUE);
2686 if (cycleThroughChoice) {
2687 SetPushedFontValue(PUSH_FONT, curFont);
2688 }
2689 } else {
2690 textCursorShown = FALSE;
2691 }
2692 ShowCurFont();
2693 ShowTextSize();
2694 UpdatePinnedMenu(MENU_FONT);
2695
2696 return TRUE;
2697 }
2698
SwitchToSingleByteFont(pStrSeg)2699 int SwitchToSingleByteFont(pStrSeg)
2700 StrSegInfo *pStrSeg;
2701 {
2702 return SwitchToSingleOrDoubleByteFont(pStrSeg);
2703 }
2704
SwitchToDoubleByteFont(pStrSeg)2705 int SwitchToDoubleByteFont(pStrSeg)
2706 StrSegInfo *pStrSeg;
2707 {
2708 return SwitchToSingleOrDoubleByteFont(pStrSeg);
2709 }
2710
2711 static
AdvanceEnd(drag)2712 void AdvanceEnd(drag)
2713 int drag;
2714 {
2715 StrBlockInfo *pStrBlock=NULL;
2716 int index=INVALID, position_end=FALSE;
2717 MiniLinesInfo *minilines=NULL;
2718 MiniLineInfo *pMiniLine=NULL;
2719
2720 position_end = BeginAdvance(drag, ADVANCE_RIGHT, &pStrBlock, &index);
2721
2722 if (pStrBlock->type == SB_SUPSUB_CENTER) {
2723 index = pStrBlock->seg->dyn_str.sz-1;
2724 EndAdvance(position_end, pStrBlock, index);
2725 } else {
2726 minilines = pStrBlock->owner_mini_line->owner_minilines;
2727 for (pMiniLine=minilines->first; pMiniLine != NULL;
2728 pMiniLine=pMiniLine->next) {
2729 if (CurStrBlockInMiniLine(pMiniLine)) {
2730 pStrBlock = pMiniLine->last_block;
2731 /* pStrBlock->type must be SB_SIMPLE */
2732 index = pStrBlock->seg->dyn_str.sz-1;
2733
2734 EndAdvance(position_end, pStrBlock, index);
2735 break;
2736 }
2737 }
2738 }
2739 AdjTextIndicesForInheritedAttr();
2740 }
2741
2742 static
HandleEnd(drag)2743 void HandleEnd(drag)
2744 int drag;
2745 {
2746 int saved_text_highlight=textHighlight;
2747
2748 if (textCursorShown && !saved_text_highlight && !drag) {
2749 EraseTextCursor();
2750 }
2751 UpdateHighLightedTextBBoxes(TRUE);
2752 if (!drag && endStrBlock != NULL) {
2753 textCurIndex = textEndIndex;
2754 curStrBlock = endStrBlock;
2755 }
2756 ResetOnCursorKey(drag);
2757
2758 AdvanceEnd(drag);
2759
2760 AdjustTextHighlight(drag, saved_text_highlight, TRUE);
2761 UpdateTextInfoChoices(FALSE);
2762 }
2763
2764 static
HandleRightMargin()2765 int HandleRightMargin()
2766 /* return TRUE if something changed */
2767 {
2768 char *psz=NULL;
2769 int right_margin=OFFSET_X(paperWidth-(rightMargin>>TIK_PER_PIXEL_SHIFTS));
2770 int x=textCurX, done=FALSE, last_index_beyond_right_margin=(-1);
2771 StrBlockInfo *psbi=NULL, *psbi_last_beyond_right_margin=NULL;
2772
2773 if (textCurX <= right_margin) return FALSE;
2774 if (textHighlight) return FALSE;
2775
2776 if (textCurIndex > 0 && curStrBlock->seg->dyn_str.s[textCurIndex-1] == ' ') {
2777 HandleCRLF(NULL);
2778 done = TRUE;
2779 }
2780 for (psbi=curStrBlock; !done && psbi != NULL; psbi=psbi->prev) {
2781 int saved_x=x;
2782
2783 if (psbi->type == SB_SIMPLE) {
2784 StrSegInfo *pssi=psbi->seg;
2785
2786 psz = strrchr(psbi->seg->dyn_str.s, ' ');
2787 while (!done && psz != NULL) {
2788 int w=0;
2789
2790 if (psz[1] == '\0') {
2791 w = 0;
2792 } else {
2793 PushCurFont();
2794 curFont = pssi->font;
2795 curSzUnit = pssi->sz_unit;
2796 curStyle = pssi->style;
2797 SetCanvasFont();
2798 w = MyTextWidth(canvasFontPtr, &psz[1], strlen(&psz[1]));
2799 PopCurFont();
2800 }
2801 if (x-w < right_margin) {
2802 /* found it! */
2803 done = TRUE;
2804 curStrBlock = psbi;
2805 textCurIndex = ((int)(psz-psbi->seg->dyn_str.s))+1;
2806 HandleCRLF(NULL);
2807 HandleEnd(FALSE);
2808 } else {
2809 char *psz2=psz, saved_ch=(*psz);
2810
2811 last_index_beyond_right_margin =
2812 ((int)(psz-psbi->seg->dyn_str.s))+1;
2813 psbi_last_beyond_right_margin = psbi;
2814 *psz2 = '\0';
2815 psz = strrchr(psbi->seg->dyn_str.s, ' ');
2816 *psz2 = saved_ch;
2817 }
2818 }
2819 }
2820 if (!done) {
2821 x = saved_x - psbi->w;
2822 }
2823 }
2824 if (!done && psbi_last_beyond_right_margin != NULL) {
2825 curStrBlock = psbi_last_beyond_right_margin;
2826 textCurIndex = last_index_beyond_right_margin;
2827 HandleCRLF(NULL);
2828 HandleEnd(FALSE);
2829 }
2830 return TRUE;
2831 }
2832
2833 static
HandleChar(Str)2834 void HandleChar(Str)
2835 char *Str;
2836 {
2837 int double_byte=FALSE, len=strlen(Str);
2838
2839 TgAssert(len <= 2, TgLoadString(STID_TOO_MANY_BYTES_IN_CH_IGNORED), NULL);
2840
2841 double_byte = (len == 2);
2842 if (canvasFontDoubleByte) {
2843 escPressed = FALSE;
2844 } else {
2845 if (escPressed) {
2846 Str[0] |= 0x80;
2847 escPressed = FALSE;
2848 }
2849 if ((((*Str)&0x80) != '\0') && curFont!=FONT_SYM && !ValidCharCode(Str)) {
2850 return;
2851 }
2852 }
2853 if (textHighlight) {
2854 curTextModified = TRUE;
2855 DeleteHighlightedText();
2856 EndChangeCurText(FALSE);
2857 SetRightMarginActive();
2858 }
2859 if (canvasFontDoubleByte != double_byte &&
2860 curStrBlock->type == SB_SUPSUB_CENTER) {
2861 XEvent ev;
2862
2863 MsgBox(TgLoadString(STID_CANT_CHNG_FONT_SUPSUB_CENTER), TOOL_NAME,
2864 INFO_MB);
2865 if (!gnDontRedrawDuringPaste) {
2866 RedrawCurText();
2867 UpdateTextInfoChoices(FALSE);
2868 }
2869 while (XCheckWindowEvent(mainDisplay, drawWindow, KeyPressMask, &ev)) ;
2870 return;
2871 } else if (canvasFontDoubleByte && !double_byte) {
2872 StrSegInfo double_byte_ssi;
2873 StrSegInfo ssi;
2874
2875 memset(&double_byte_ssi, 0, sizeof(StrSegInfo));
2876 memcpy(&double_byte_ssi, curStrBlock->seg, sizeof(StrSegInfo));
2877 memset(&ssi, 0, sizeof(StrSegInfo));
2878 if (CanFindSingleByteFontAtCursor(&ssi)) {
2879 if (SwitchToSingleByteFont(&ssi)) {
2880 SetCopyUTF8FontInfo(&double_byte_ssi, TRUE);
2881 double_byte = FALSE;
2882 }
2883 } else if (gstCopyUTF8Info.single_byte_valid) {
2884 if (SwitchToSingleByteFont(&gstCopyUTF8Info.single_byte_seg)) {
2885 SetCopyUTF8FontInfo(&double_byte_ssi, TRUE);
2886 double_byte = FALSE;
2887 }
2888 } else {
2889 ssi.font = GetInitialFont();
2890 ssi.style = curStyle;
2891 ssi.sz_unit = curSzUnit;
2892 if (SwitchToSingleByteFont(&ssi)) {
2893 SetCopyUTF8FontInfo(&double_byte_ssi, TRUE);
2894 double_byte = FALSE;
2895 }
2896 }
2897 } else if (!canvasFontDoubleByte && double_byte) {
2898 StrSegInfo single_byte_ssi;
2899 StrSegInfo ssi;
2900
2901 memset(&single_byte_ssi, 0, sizeof(StrSegInfo));
2902 memcpy(&single_byte_ssi, curStrBlock->seg, sizeof(StrSegInfo));
2903 memset(&ssi, 0, sizeof(StrSegInfo));
2904 if (CanFindDoubleByteFontAtCursor(&ssi)) {
2905 if (SwitchToDoubleByteFont(&ssi)) {
2906 SetCopyUTF8FontInfo(&single_byte_ssi, FALSE);
2907 double_byte = TRUE;
2908 }
2909 } else if (gstCopyUTF8Info.double_byte_valid) {
2910 if (SwitchToDoubleByteFont(&gstCopyUTF8Info.double_byte_seg)) {
2911 SetCopyUTF8FontInfo(&single_byte_ssi, FALSE);
2912 double_byte = TRUE;
2913 }
2914 }
2915 }
2916 if (!InsertCharIntoCurText(Str, double_byte)) {
2917 XEvent ev;
2918
2919 if (!gnDontRedrawDuringPaste) {
2920 RedrawCurText();
2921 UpdateTextInfoChoices(FALSE);
2922 }
2923 while (XCheckWindowEvent(mainDisplay, drawWindow, KeyPressMask, &ev)) ;
2924 return;
2925 }
2926 if ((rightMarginEnabled == TRUE) && rightMarginActive) {
2927 /* add a <CR> somewhere */
2928 HandleRightMargin();
2929 }
2930 if (gnDontRedrawDuringPaste) {
2931 if ((rightMarginEnabled == TRUE) && rightMarginActive) {
2932 gnDontRedrawDuringPaste = FALSE;
2933 }
2934 }
2935 if (!gnDontRedrawDuringPaste) {
2936 ScrollTo(textCurX, textCurBaselineY);
2937 }
2938 }
2939
2940 static
HandleTAB(key_ev)2941 void HandleTAB(key_ev)
2942 XKeyEvent *key_ev;
2943 {
2944 struct AttrRec *attr_ptr=NULL, *new_attr=NULL;
2945 struct ObjRec *obj_ptr=NULL;
2946 int abs_x=0, abs_y=0, x_off=0, y_off=0;
2947
2948 escPressed = FALSE;
2949
2950 if ((attr_ptr=curTextObj->detail.t->attr) == NULL) {
2951 MsgBox(TgLoadString(STID_CANT_TAB_OUT_OF_NON_ATTR_TEXT), TOOL_NAME,
2952 INFO_MB);
2953 return;
2954 }
2955 CreateTextObj(TRUE, TRUE);
2956 curTextModified = FALSE;
2957
2958 if (key_ev != NULL && (key_ev->state & METAMASK) != 0) {
2959 /* new_attr will be the next attribute */
2960 if (attr_ptr->next == NULL) {
2961 new_attr = attr_ptr->owner->fattr;
2962 } else {
2963 new_attr = attr_ptr->next;
2964 }
2965 while (!new_attr->shown) {
2966 if (new_attr->next == NULL) {
2967 new_attr = new_attr->owner->fattr;
2968 } else {
2969 new_attr = new_attr->next;
2970 }
2971 }
2972 } else {
2973 /* new_attr will be the previous attribute */
2974 if (attr_ptr->prev == NULL) {
2975 new_attr = attr_ptr->owner->lattr;
2976 } else {
2977 new_attr = attr_ptr->prev;
2978 }
2979 while (!new_attr->shown) {
2980 if (new_attr->prev == NULL) {
2981 new_attr = new_attr->owner->lattr;
2982 } else {
2983 new_attr = new_attr->prev;
2984 }
2985 }
2986 }
2987 obj_ptr = new_attr->obj;
2988 abs_x = obj_ptr->x; x_off = OFFSET_X(abs_x);
2989 abs_y = obj_ptr->y; y_off = OFFSET_Y(abs_y);
2990
2991 if (!PrepareEditExistingText(obj_ptr, abs_x, abs_y, &x_off, &y_off)) {
2992 return;
2993 }
2994 if (curStrBlock != NULL) UpdateHighLightedTextBBoxes(TRUE);
2995 HandleClickOnText(FALSE, TRUE, x_off, y_off, FALSE, obj_ptr, FALSE, TRUE,
2996 FALSE, (Time)0);
2997 UpdateTextInfoChoices(TRUE);
2998 }
2999
3000 static
AdvanceHome(drag)3001 void AdvanceHome(drag)
3002 int drag;
3003 {
3004 StrBlockInfo *pStrBlock=NULL;
3005 int index=INVALID, position_end=FALSE;
3006 MiniLinesInfo *minilines=NULL;
3007 MiniLineInfo *pMiniLine=NULL;
3008
3009 position_end = BeginAdvance(drag, ADVANCE_LEFT, &pStrBlock, &index);
3010
3011 if (pStrBlock->type == SB_SUPSUB_CENTER) {
3012 EndAdvance(position_end, pStrBlock, 0);
3013 } else {
3014 minilines = pStrBlock->owner_mini_line->owner_minilines;
3015 for (pMiniLine=minilines->first; pMiniLine != NULL;
3016 pMiniLine=pMiniLine->next) {
3017 if (CurStrBlockInMiniLine(pMiniLine)) {
3018 EndAdvance(position_end, pMiniLine->first_block, 0);
3019 break;
3020 }
3021 }
3022 }
3023 AdjTextIndicesForInheritedAttr();
3024 }
3025
3026 static
HandleHome(drag)3027 void HandleHome(drag)
3028 int drag;
3029 {
3030 int saved_text_highlight=textHighlight;
3031
3032 if (textCursorShown && !saved_text_highlight && !drag) {
3033 EraseTextCursor();
3034 }
3035 UpdateHighLightedTextBBoxes(TRUE);
3036 ResetOnCursorKey(drag);
3037
3038 AdvanceHome(drag);
3039
3040 AdjustTextHighlight(drag, saved_text_highlight, TRUE);
3041 UpdateTextInfoChoices(FALSE);
3042 }
3043
3044 static
CanMoveTextCursorIntoLeftScripts()3045 int CanMoveTextCursorIntoLeftScripts()
3046 {
3047 if (textCursorShown && curStrBlock != NULL && textCurIndex == 0 &&
3048 curStrBlock->prev != NULL &&
3049 (curStrBlock->prev->type == SB_SUPSUB_LEFT ||
3050 curStrBlock->prev->type == SB_SUPSUB_CENTER ||
3051 curStrBlock->prev->type == SB_SUPSUB_RIGHT)) {
3052 return TRUE;
3053 }
3054 return FALSE;
3055 }
3056
3057 static
DoMoveTextCursorIntoLeftScripts()3058 void DoMoveTextCursorIntoLeftScripts()
3059 {
3060 int saved_text_highlight=textHighlight;
3061
3062 if (textCursorShown && !saved_text_highlight) {
3063 EraseTextCursor();
3064 }
3065 UpdateHighLightedTextBBoxes(TRUE);
3066
3067 curStrBlock = curStrBlock->prev->sup->first->last_block;
3068
3069 textCurIndex = curStrBlock->seg->dyn_str.sz-1;
3070 ResetOnCursorKey(FALSE);
3071 SetTextCurXY();
3072 SetTextHighlight();
3073 UpdatePinnedMenu(MENU_EDIT);
3074 if (textCursorShown && !saved_text_highlight) {
3075 PutTextCursor();
3076 } else {
3077 RedrawCurText();
3078 }
3079 MarkRulers(textCurX, textCurY);
3080 ScrollTo(textCurX, textCurBaselineY);
3081 UpdateTextInfoChoices(FALSE);
3082 }
3083
3084 static
HandleLeft(key_ev)3085 void HandleLeft(key_ev)
3086 XKeyEvent *key_ev;
3087 {
3088 int saved_text_highlight=textHighlight;
3089 int cycle=((key_ev->state & ControlMask) != 0);
3090 int drag=((key_ev->state & ShiftMask) != 0);
3091
3092 if (cycle) {
3093 if (CanMoveTextCursorIntoLeftScripts()) {
3094 DoMoveTextCursorIntoLeftScripts();
3095 }
3096 return;
3097 }
3098 if (textCursorShown && !saved_text_highlight && !drag) {
3099 EraseTextCursor();
3100 } else if (textCursorShown && saved_text_highlight && !drag) {
3101 if (FixHighlightedStrBlockDepths() < 0) {
3102 SwitchTextCurAndEndStrBlocks();
3103 }
3104 }
3105 UpdateHighLightedTextBBoxes(TRUE);
3106 ResetOnCursorKey(drag);
3107
3108 AdvanceLeft(drag);
3109
3110 AdjustTextHighlight(drag, saved_text_highlight, TRUE);
3111 UpdateTextInfoChoices(FALSE);
3112 }
3113
3114 static
CanCycleTextCursorInScripts()3115 int CanCycleTextCursorInScripts()
3116 {
3117 return (textCursorShown && curStrBlock != NULL && curStrBlock->depth != 0);
3118 }
3119
3120 static
DoCycleTextCursorInScripts(direction)3121 void DoCycleTextCursorInScripts(direction)
3122 int direction;
3123 {
3124 int saved_text_highlight=textHighlight;
3125 MiniLinesInfo *pOwnerMinilines=NULL;
3126 StrBlockInfo *pOwnerStrBlock=NULL;
3127
3128 if (textCursorShown && !saved_text_highlight) {
3129 EraseTextCursor();
3130 }
3131 UpdateHighLightedTextBBoxes(TRUE);
3132 ResetOnCursorKey(FALSE);
3133
3134 switch(curStrBlock->type) {
3135 case SB_SIMPLE:
3136 pOwnerMinilines = curStrBlock->owner_mini_line->owner_minilines;
3137 pOwnerStrBlock = pOwnerMinilines->owner_block;
3138
3139 switch (pOwnerStrBlock->type) {
3140 case SB_SUPSUB_LEFT:
3141 case SB_SUPSUB_RIGHT:
3142 if (pOwnerMinilines == pOwnerStrBlock->sup) {
3143 curStrBlock = pOwnerStrBlock->sub->first->first_block;
3144 } else if (pOwnerMinilines == pOwnerStrBlock->sub) {
3145 curStrBlock = pOwnerStrBlock->sup->first->first_block;
3146 } else {
3147 if (textCursorShown && !saved_text_highlight) {
3148 PutTextCursor();
3149 }
3150 return;
3151 }
3152 break;
3153 case SB_SUPSUB_CENTER:
3154 if (pOwnerMinilines == pOwnerStrBlock->sup) {
3155 if (direction == SCROLL_UP) {
3156 curStrBlock = pOwnerStrBlock->sub->first->first_block;
3157 } else {
3158 curStrBlock = pOwnerStrBlock;
3159 }
3160 } else if (pOwnerMinilines == pOwnerStrBlock->sub) {
3161 if (direction == SCROLL_UP) {
3162 curStrBlock = pOwnerStrBlock;
3163 } else {
3164 curStrBlock = pOwnerStrBlock->sup->first->first_block;
3165 }
3166 } else {
3167 if (textCursorShown && !saved_text_highlight) {
3168 PutTextCursor();
3169 }
3170 return;
3171 }
3172 break;
3173 }
3174 break;
3175
3176 case SB_CHAR_SPACE: /* not possible */
3177 case SB_SUPSUB_LEFT: /* not possible */
3178 case SB_SUPSUB_RIGHT: /* not possible */
3179 if (textCursorShown && !saved_text_highlight) {
3180 PutTextCursor();
3181 }
3182 return;
3183
3184 case SB_SUPSUB_CENTER:
3185 if (curStrBlock->sub != NULL) {
3186 if (direction == SCROLL_UP) {
3187 curStrBlock = curStrBlock->sup->first->first_block;
3188 } else {
3189 curStrBlock = curStrBlock->sub->first->first_block;
3190 }
3191 } else {
3192 if (textCursorShown && !saved_text_highlight) {
3193 PutTextCursor();
3194 }
3195 return;
3196 }
3197 break;
3198 }
3199 textCurIndex = 0;
3200 SetTextCurXY();
3201 SetTextHighlight();
3202 UpdatePinnedMenu(MENU_EDIT);
3203 if (textCursorShown && !saved_text_highlight) {
3204 PutTextCursor();
3205 } else {
3206 RedrawCurText();
3207 }
3208 MarkRulers(textCurX, textCurY);
3209 ScrollTo(textCurX, textCurBaselineY);
3210 UpdateTextInfoChoices(FALSE);
3211 }
3212
3213 static
HandleUp(key_ev)3214 void HandleUp(key_ev)
3215 XKeyEvent *key_ev;
3216 {
3217 int saved_text_highlight=textHighlight;
3218 int cycle=((key_ev->state & ControlMask) != 0);
3219 int drag=((key_ev->state & ShiftMask) != 0), new_x_off=0, new_y_off=0;
3220
3221 if (cycle) {
3222 if (CanCycleTextCursorInScripts()) {
3223 DoCycleTextCursorInScripts(SCROLL_UP);
3224 }
3225 return;
3226 }
3227 if (textCursorShown && !saved_text_highlight && !drag) {
3228 EraseTextCursor();
3229 }
3230 UpdateHighLightedTextBBoxes(TRUE);
3231 ResetOnCursorKey(drag);
3232
3233 if (drag && textHighlight) {
3234 new_x_off = textEndX;
3235 if (endStrBlock->type == SB_SUPSUB_CENTER) {
3236 new_y_off = textEndBaselineY-endStrBlock->seg->asc-2;
3237 } else {
3238 MiniLineInfo *pOwnerMiniLine=endStrBlock->owner_mini_line;
3239
3240 new_y_off = textEndBaselineY - pOwnerMiniLine->asc -
3241 pOwnerMiniLine->v_gap - 2;
3242 if (pOwnerMiniLine->owner_minilines != NULL &&
3243 pOwnerMiniLine->owner_minilines->owner_block == NULL) {
3244 new_y_off -= pOwnerMiniLine->owner_minilines->v_space;
3245 }
3246 }
3247 } else {
3248 new_x_off = textCurX;
3249 if (curStrBlock->type == SB_SUPSUB_CENTER) {
3250 new_y_off = textCurBaselineY-curStrBlock->seg->asc-2;
3251 } else {
3252 MiniLineInfo *pOwnerMiniLine=curStrBlock->owner_mini_line;
3253
3254 new_y_off = textCurBaselineY - pOwnerMiniLine->asc -
3255 pOwnerMiniLine->v_gap - 2;
3256 if (pOwnerMiniLine->owner_minilines != NULL &&
3257 pOwnerMiniLine->owner_minilines->owner_block == NULL) {
3258 new_y_off -= pOwnerMiniLine->owner_minilines->v_space;
3259 }
3260 }
3261 }
3262 HandleClickOnText(drag, TRUE, new_x_off, new_y_off, TRUE, curTextObj, FALSE,
3263 saved_text_highlight, FALSE, key_ev->time);
3264 UpdateTextInfoChoices(FALSE);
3265 }
3266
3267 static
CanMoveTextCursorIntoRightScripts()3268 int CanMoveTextCursorIntoRightScripts()
3269 {
3270 if (textCursorShown && curStrBlock != NULL &&
3271 textCurIndex == curStrBlock->seg->dyn_str.sz-1 &&
3272 curStrBlock->next != NULL &&
3273 (curStrBlock->next->type == SB_SUPSUB_LEFT ||
3274 curStrBlock->next->type == SB_SUPSUB_CENTER ||
3275 curStrBlock->next->type == SB_SUPSUB_RIGHT)) {
3276 return TRUE;
3277 }
3278 return FALSE;
3279 }
3280
3281 static
DoMoveTextCursorIntoRightScripts()3282 void DoMoveTextCursorIntoRightScripts()
3283 {
3284 int saved_text_highlight=textHighlight;
3285
3286 if (textCursorShown && !saved_text_highlight) {
3287 EraseTextCursor();
3288 }
3289 UpdateHighLightedTextBBoxes(TRUE);
3290
3291 curStrBlock = curStrBlock->next->sup->first->first_block;
3292
3293 textCurIndex = 0;
3294 ResetOnCursorKey(FALSE);
3295 SetTextCurXY();
3296 SetTextHighlight();
3297 UpdatePinnedMenu(MENU_EDIT);
3298 if (textCursorShown && !saved_text_highlight) {
3299 PutTextCursor();
3300 } else {
3301 RedrawCurText();
3302 }
3303 MarkRulers(textCurX, textCurY);
3304 ScrollTo(textCurX, textCurBaselineY);
3305 UpdateTextInfoChoices(FALSE);
3306 }
3307
3308 static
HandleRight(key_ev)3309 void HandleRight(key_ev)
3310 XKeyEvent *key_ev;
3311 {
3312 int saved_text_highlight=textHighlight;
3313 int cycle=((key_ev->state & ControlMask) != 0);
3314 int drag=((key_ev->state & ShiftMask) != 0);
3315
3316 if (cycle) {
3317 if (CanMoveTextCursorIntoRightScripts()) {
3318 DoMoveTextCursorIntoRightScripts();
3319 }
3320 return;
3321 }
3322 if (textCursorShown && !saved_text_highlight && !drag) {
3323 EraseTextCursor();
3324 } else if (textCursorShown && saved_text_highlight && !drag) {
3325 if (FixHighlightedStrBlockDepths() < 0) {
3326 SwitchTextCurAndEndStrBlocks();
3327 }
3328 }
3329 UpdateHighLightedTextBBoxes(TRUE);
3330 if (!drag && endStrBlock != NULL) {
3331 textCurIndex = textEndIndex;
3332 curStrBlock = endStrBlock;
3333 }
3334 ResetOnCursorKey(drag);
3335
3336 AdvanceRight(drag);
3337
3338 AdjustTextHighlight(drag, saved_text_highlight, TRUE);
3339 UpdateTextInfoChoices(FALSE);
3340 }
3341
3342 static
HandleDown(key_ev)3343 void HandleDown(key_ev)
3344 XKeyEvent *key_ev;
3345 {
3346 int saved_text_highlight=textHighlight;
3347 int cycle=((key_ev->state & ControlMask) != 0);
3348 int drag=((key_ev->state & ShiftMask) != 0), new_x_off=0, new_y_off=0;
3349
3350 if (cycle) {
3351 if (CanCycleTextCursorInScripts()) {
3352 DoCycleTextCursorInScripts(SCROLL_DOWN);
3353 }
3354 return;
3355 }
3356 if (textCursorShown && !saved_text_highlight && !drag) {
3357 EraseTextCursor();
3358 }
3359 UpdateHighLightedTextBBoxes(TRUE);
3360 ResetOnCursorKey(drag);
3361
3362 if (drag && textHighlight) {
3363 new_x_off = textEndX;
3364 if (endStrBlock->type == SB_SUPSUB_CENTER) {
3365 new_y_off = textEndBaselineY+endStrBlock->seg->des+2;
3366 } else {
3367 MiniLineInfo *pOwnerMiniLine=endStrBlock->owner_mini_line;
3368
3369 new_y_off = textEndBaselineY+pOwnerMiniLine->des+2;
3370 if (pOwnerMiniLine->owner_minilines != NULL &&
3371 pOwnerMiniLine->owner_minilines->owner_block == NULL) {
3372 new_y_off += pOwnerMiniLine->owner_minilines->v_space;
3373 }
3374 if (pOwnerMiniLine->next != NULL) {
3375 new_y_off += pOwnerMiniLine->v_gap;
3376 }
3377 }
3378 } else {
3379 new_x_off = textCurX;
3380 if (curStrBlock->type == SB_SUPSUB_CENTER) {
3381 new_y_off = textCurBaselineY+curStrBlock->seg->des+2;
3382 } else {
3383 MiniLineInfo *pOwnerMiniLine=curStrBlock->owner_mini_line;
3384
3385 new_y_off = textCurBaselineY+pOwnerMiniLine->des+2;
3386 if (pOwnerMiniLine->owner_minilines != NULL &&
3387 pOwnerMiniLine->owner_minilines->owner_block == NULL) {
3388 new_y_off += pOwnerMiniLine->owner_minilines->v_space;
3389 }
3390 if (pOwnerMiniLine->next != NULL) {
3391 new_y_off += pOwnerMiniLine->v_gap;
3392 }
3393 }
3394 }
3395 HandleClickOnText(drag, TRUE, new_x_off, new_y_off, TRUE, curTextObj, FALSE,
3396 saved_text_highlight, FALSE, key_ev->time);
3397 UpdateTextInfoChoices(FALSE);
3398 }
3399
3400 static
DoHandleInputFromBuffer(cut_buffer)3401 void DoHandleInputFromBuffer(cut_buffer)
3402 char *cut_buffer;
3403 {
3404 char *c_ptr=NULL, s[80];
3405
3406 s[2] = '\0';
3407 for (c_ptr = cut_buffer; *c_ptr != '\0'; c_ptr+=2) {
3408 int double_byte=FALSE;
3409
3410 if (((*c_ptr) & 0x80) == '\0') {
3411 s[0] = c_ptr[0];
3412 s[1] = '\0';
3413 } else {
3414 double_byte = TRUE;
3415
3416 if (!canvasFontDoubleByte && double_byte) {
3417 StrSegInfo ssi;
3418
3419 memset(&ssi, 0, sizeof(StrSegInfo));
3420 if (!CanFindDoubleByteFontAtCursor(&ssi) &&
3421 !gstCopyUTF8Info.double_byte_valid) {
3422 double_byte = FALSE;
3423 }
3424 }
3425 if (double_byte) {
3426 s[0] = c_ptr[0];
3427 s[1] = c_ptr[1];
3428 } else {
3429 s[0] = c_ptr[0];
3430 s[1] = '\0';
3431 }
3432 }
3433 switch (s[0]) {
3434 case '\r':
3435 case '\n': HandleCRLF(NULL); c_ptr--; break;
3436
3437 case '\177': Msg(TgLoadCachedString(CSTID_CANT_PASTE_DEL)); break;
3438 case '\b': Msg(TgLoadCachedString(CSTID_CANT_PASTE_BS)); break;
3439 case '\033': Msg(TgLoadCachedString(CSTID_CANT_PASTE_ESC)); break;
3440
3441 case '\t':
3442 Msg(TgLoadCachedString(CSTID_CANT_PASTE_TAB_REPLACE_BY_SPC));
3443 s[0] = ' ';
3444 /* drop through */
3445 default:
3446 HandleChar(s);
3447 if (!double_byte) {
3448 c_ptr--;
3449 }
3450 break;
3451 }
3452 }
3453 }
3454
HandleInputFromBuffer(cut_buffer)3455 void HandleInputFromBuffer(cut_buffer)
3456 char *cut_buffer;
3457 {
3458 if (cut_buffer == NULL || *cut_buffer == '\0') return;
3459
3460 SaveStatusStrings();
3461 gnPastingLineNum = 0;
3462 if (!((rightMarginEnabled == TRUE) && rightMarginActive)) {
3463 gnDontRedrawDuringPaste = TRUE;
3464 }
3465 DoHandleInputFromBuffer(cut_buffer);
3466 gnDontRedrawDuringPaste = FALSE;
3467 RestoreStatusStrings();
3468
3469 UpdTextBBox(curTextObj);
3470 SetTextCurXY();
3471 if (textHighlight) SetTextEndXY();
3472 UpdateEditTextArea(
3473 curTextObj->detail.t->minilines.w,
3474 curTextObj->detail.t->minilines.h,
3475 curTextObj->detail.t->minilines.min_lbearing,
3476 curTextObj->detail.t->minilines.max_rextra);
3477
3478 RedrawCurText();
3479 ScrollTo(textCurX, textCurBaselineY);
3480 MarkRulers(textCurX, textCurY);
3481 SetFileModified(TRUE);
3482 UpdateTextInfoChoices(FALSE);
3483
3484 return;
3485 }
3486
HandleTextFromBuffer(key_ev,s,key_sym,has_ch)3487 void HandleTextFromBuffer(key_ev, s, key_sym, has_ch)
3488 XKeyEvent *key_ev;
3489 char *s;
3490 KeySym key_sym;
3491 int has_ch;
3492 {
3493 int drag=FALSE, cursor_key=FALSE;
3494
3495 ResetDirtyBBoxInfo();
3496
3497 if (CharIsCntrlShiftINS(key_ev, key_sym)) {
3498 char szBuf[MAXSTRING];
3499 int nBufSize=sizeof(szBuf);
3500
3501 memset(szBuf, 0, sizeof(szBuf));
3502 if (InputOctalString(szBuf, &nBufSize)) {
3503 HandleInputFromBuffer(szBuf);
3504 }
3505 } else if (CharIsESC(key_ev, s, key_sym, &has_ch) ||
3506 CharIsCRorLF(key_ev, s, key_sym, &has_ch) ||
3507 CharIsBSorDEL(key_ev, s, key_sym, &has_ch, FALSE) ||
3508 CharIsTAB(key_ev, s, key_sym, &has_ch) ||
3509 CharIsHome(key_ev, s, key_sym, &has_ch) ||
3510 CharIsEnd(key_ev, s, key_sym, &has_ch)) {
3511 } else if (!((s[0]=='\r' && (key_sym & 0xff)=='\r') ||
3512 (s[0]=='\n' && (key_sym & 0xff)=='\n') ||
3513 (s[0]=='\b' && (key_sym & 0xff)=='\b') ||
3514 (s[0]=='\b' && (key_sym & 0xff)=='h' &&
3515 (key_ev != NULL && (key_ev->state & ControlMask))) ||
3516 key_sym==XK_Left || key_sym==XK_Up ||
3517 key_sym==XK_Right || key_sym==XK_Down ||
3518 key_sym==XK_KP_Left || key_sym==XK_KP_Up ||
3519 key_sym==XK_KP_Right || key_sym==XK_KP_Down ||
3520 (key_sym==XK_Tab &&
3521 (key_ev != NULL && (key_ev->state & (ShiftMask | METAMASK)) != 0)) ||
3522 (s[0]=='\033' && (key_sym & 0xff)=='\033') ||
3523 (s[0]=='\177' && (key_sym & 0x7f)=='\177') ||
3524 ((s[0]&0xff) && canvasFontDoubleByte) ||
3525 (has_ch==1 && ((unsigned char)s[0])>='\040'))) {
3526 return;
3527 }
3528 drag = ((key_ev->state & ShiftMask) != 0);
3529
3530 switch (key_sym) {
3531 case XK_Left: HandleLeft(key_ev); cursor_key = TRUE; break;
3532 case XK_KP_Left: HandleLeft(key_ev); cursor_key = TRUE; break;
3533 case XK_Up: HandleUp(key_ev); cursor_key = TRUE; break;
3534 case XK_KP_Up: HandleUp(key_ev); cursor_key = TRUE; break;
3535 case XK_Right: HandleRight(key_ev); cursor_key = TRUE; break;
3536 case XK_KP_Right: HandleRight(key_ev); cursor_key = TRUE; break;
3537 case XK_Down: HandleDown(key_ev); cursor_key = TRUE; break;
3538 case XK_KP_Down: HandleDown(key_ev); cursor_key = TRUE; break;
3539 default:
3540 if (!canvasFontDoubleByte) {
3541 s[1] = '\0';
3542 }
3543 if (CharIsESC(key_ev, s, key_sym, &has_ch)) {
3544 if (!escPressed) {
3545 escPressed = TRUE;
3546 return;
3547 }
3548 } else if (CharIsCRorLF(key_ev, s, key_sym, &has_ch)) {
3549 HandleCRLF(key_ev);
3550 } else if (CharIsBSorDEL(key_ev, s, key_sym, &has_ch, FALSE)) {
3551 if (has_ch && s[0] == '\177') {
3552 if (escPressed) {
3553 HandleChar(s);
3554 } else {
3555 HandleBS(key_ev, s, key_sym, &has_ch);
3556 }
3557 } else {
3558 HandleBS(key_ev, s, key_sym, &has_ch);
3559 }
3560 } else if (CharIsTAB(key_ev, s, key_sym, &has_ch)) {
3561 HandleTAB(key_ev);
3562 cursor_key = TRUE;
3563 } else if (CharIsHome(key_ev, s, key_sym, &has_ch)) {
3564 HandleHome(drag);
3565 cursor_key = TRUE;
3566 } else if (CharIsEnd(key_ev, s, key_sym, &has_ch)) {
3567 HandleEnd(drag);
3568 cursor_key = TRUE;
3569 } else if (has_ch) {
3570 if (canvasFontDoubleByte) {
3571 char ch[3], *c_ptr=NULL;
3572
3573 ch[2] = '\0';
3574 for (c_ptr=s; *c_ptr != '\0'; c_ptr++) {
3575 int double_byte=((*c_ptr)&0x80);
3576
3577 ch[0] = c_ptr[0];
3578 if (double_byte) {
3579 ch[1] = *(++c_ptr);
3580 } else {
3581 ch[1] = '\0';
3582 }
3583 HandleChar(ch);
3584 }
3585 } else {
3586 HandleChar(s);
3587 }
3588 }
3589 break;
3590 }
3591 if (textCursorShown) {
3592 MarkRulers(textCurX, textCurY);
3593 if (!cursor_key) SetFileModified(TRUE);
3594 }
3595 }
3596
3597 static
HandlePasteInDrawTextMode()3598 void HandlePasteInDrawTextMode()
3599 {
3600 char *cut_buffer=NULL;
3601 int xfree_cut_buffer=FALSE;
3602 int len=0;
3603
3604 if (pasteFromFileInDrawTextMode) {
3605 FILE *fp;
3606 char inbuf[MAXSTRING+1];
3607 int size=0;
3608
3609 pasteFromFileInDrawTextMode = FALSE;
3610 if ((fp=fopen(pasteFromFileName, "r")) == NULL) {
3611 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_READING),
3612 pasteFromFileName);
3613 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3614 return;
3615 }
3616 while (fgets(inbuf, MAXSTRING, fp) != NULL) size += strlen(inbuf);
3617 fclose(fp);
3618 if (size == 0) {
3619 sprintf(gszMsgBox, TgLoadString(STID_NAMED_FILE_IS_EMPTY),
3620 pasteFromFileName);
3621 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3622 return;
3623 }
3624 cut_buffer = (char*)malloc((size+2)*sizeof(char));
3625 if (cut_buffer == NULL) {
3626 FailAllocMessage();
3627 return;
3628 }
3629 memset(cut_buffer, 0, (size+2)*sizeof(char));
3630 if ((fp=fopen(pasteFromFileName, "r")) == NULL) {
3631 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_READING),
3632 pasteFromFileName);
3633 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3634 free(cut_buffer);
3635 return;
3636 }
3637 len = 0;
3638 while (fgets(&cut_buffer[len], MAXSTRING, fp) != NULL) {
3639 len += strlen(&cut_buffer[len]);
3640 }
3641 fclose(fp);
3642 #ifndef _NO_NKF
3643 if (Tg_useNKF()) {
3644 char *out_buffer=(char*)malloc(size+2);
3645
3646 if (out_buffer == NULL) FailAllocMessage();
3647 Tg_do_kconv(cut_buffer, out_buffer, size+2);
3648 strcpy(cut_buffer, out_buffer);
3649 free(out_buffer);
3650 } else {
3651 #ifndef _NO_KINPUT
3652 if (copyAndPasteJIS) {
3653 CvtJisToEuc(cut_buffer, cut_buffer);
3654 }
3655 #endif /* ~_NO_KINPUT */
3656 }
3657 #endif /* ~_NO_NKF */
3658 } else if (pasteCompoundTextInDrawTextMode) {
3659 unsigned long ul=0L;
3660
3661 pasteCompoundTextInDrawTextMode = FALSE;
3662 cut_buffer = GetTextBytesFromSelection(TRUE, &ul);
3663 if (cut_buffer == NULL || ul == 0L) {
3664 Msg(TgLoadString(STID_COMPOUND_TEXT_BUF_IS_EMPTY));
3665 if (cut_buffer != NULL) UtilFree(cut_buffer);
3666 return;
3667 }
3668 } else {
3669 int from_selection=FALSE;
3670
3671 cut_buffer = FetchSelectionOrCutBuffer(&len, &from_selection);
3672 if (cut_buffer == NULL) {
3673 Msg(TgLoadString(STID_CUT_BUFFER_IS_EMPTY));
3674 return;
3675 }
3676 xfree_cut_buffer = !from_selection;
3677 #ifndef _NO_KINPUT
3678 if (copyAndPasteJIS) {
3679 CvtJisToEuc(cut_buffer, cut_buffer);
3680 }
3681 #endif /* ~_NO_KINPUT */
3682 }
3683
3684 if (escPressed) {
3685 escPressed = FALSE;
3686 Msg(TgLoadString(STID_AN_ESC_KEY_PRESS_IGNORED));
3687 }
3688 HandleInputFromBuffer(cut_buffer);
3689
3690 if (gnPastingLineNum > 0) {
3691 sprintf(gszMsgBox, TgLoadString(STID_GIVEN_NUM_LINES_PASTED),
3692 gnPastingLineNum);
3693 Msg(gszMsgBox);
3694 }
3695 FreeSelectionOrCutBuffer(cut_buffer, !xfree_cut_buffer);
3696 }
3697
3698 static
HandleCopyInDrawTextMode()3699 void HandleCopyInDrawTextMode()
3700 {
3701 int copy_failed=FALSE, copy_db_utf8_str=FALSE;
3702 int cut_buffer_size=0, double_byte_font_index=INVALID;
3703 char *cut_buffer=NULL;
3704
3705 if (!textHighlight) return;
3706
3707 if (escPressed) {
3708 escPressed = FALSE;
3709 Msg(TgLoadString(STID_AN_ESC_KEY_PRESS_IGNORED));
3710 }
3711 if (copyDoubleByteStringInDrawTextMode &&
3712 CanCopyHighLightedTextAsUTF8Strings(&double_byte_font_index)) {
3713 /* copy just text, cut_buffer_size will include terminating '\0' */
3714 GatherHighLightedTextAsStrings(&cut_buffer, &cut_buffer_size);
3715 copy_db_utf8_str = TRUE;
3716 } else if (CanCopyHighLightedTextAsStrings()) {
3717 /* copy just text, cut_buffer_size will include terminating '\0' */
3718 GatherHighLightedTextAsStrings(&cut_buffer, &cut_buffer_size);
3719 } else {
3720 #ifdef _TGIF_DBG /* debug, do not translate */
3721 TgAssert(FALSE,
3722 "Can only handle simple text in HandleCopyInDrawTextMode()", NULL);
3723 #endif /* _TGIF_DBG */
3724 }
3725 if (cut_buffer == NULL) {
3726 ClearSelection();
3727 return;
3728 }
3729 #ifndef _NO_KINPUT
3730 if (!copy_db_utf8_str && canvasFontDoubleByte &&
3731 gnInputMethod == TGIM_KINPUT && copyAndPasteJIS) {
3732 char *tmp_buffer=NULL;
3733
3734 cut_buffer_size = CvtEucToJis(NULL, cut_buffer);
3735 tmp_buffer = (char*)malloc((cut_buffer_size+2)*sizeof(char));
3736 CvtEucToJis(tmp_buffer, cut_buffer);
3737 free(cut_buffer);
3738 cut_buffer = tmp_buffer;
3739 }
3740 #endif /* ~_NO_KINPUT */
3741 if (copy_db_utf8_str && (double_byte_font_index != INVALID)) {
3742 if (!ConvertToOrFromUTF8(CONVERT_TO_UTF8, double_byte_font_index, &cut_buffer)) {
3743 ClearSelection();
3744 return;
3745 }
3746 cut_buffer_size = strlen(cut_buffer)+1;
3747 }
3748 copy_failed = !WriteBufToCutBuffer(cut_buffer, cut_buffer_size-1, TRUE,
3749 copy_db_utf8_str && (double_byte_font_index != INVALID), NULL);
3750
3751 if (copy_failed) {
3752 sprintf(gszMsgBox, TgLoadString(STID_COPY_FAIL_SEL_STR_MAY_TOO_LNG));
3753 } else {
3754 sprintf(gszMsgBox, TgLoadString(STID_COPY_BUFFER_UPDATED));
3755 }
3756 Msg(gszMsgBox);
3757 free(cut_buffer);
3758 }
3759
3760 static
HandleFunctionKey(key_sym)3761 int HandleFunctionKey(key_sym)
3762 KeySym key_sym;
3763 {
3764 int index=0;
3765 char buf[MAXSTRING], *c_ptr=NULL, tmp_fname[MAXSTRING+1];
3766 FILE *fp=NULL;
3767
3768 switch (key_sym) {
3769 case XK_F1: index=1; break;
3770 case XK_F2: index=2; break;
3771 case XK_F3: index=3; break;
3772 case XK_F4: index=4; break;
3773 case XK_F5: index=5; break;
3774 case XK_F6: index=6; break;
3775 case XK_F7: index=7; break;
3776 case XK_F8: index=8; break;
3777 case XK_F9: index=9; break;
3778 case XK_F10: index=10; break;
3779 case XK_F11: index=11; break;
3780 case XK_F12: index=12; break;
3781 default: return FALSE;
3782 }
3783 sprintf(buf, "DrawTextFuncKey_F%1d", index);
3784 if ((c_ptr=XGetDefault(mainDisplay, TOOL_NAME, buf)) == NULL) {
3785 return FALSE;
3786 }
3787 if (MkTempFile(tmp_fname, sizeof(tmp_fname), tmpDir, TOOL_NAME) ==
3788 NULL) {
3789 return TRUE;
3790 }
3791 if ((fp=fopen(tmp_fname, "w")) == NULL) {
3792 FailToWriteFileMessage(tmp_fname);
3793 return TRUE;
3794 }
3795 fprintf(fp, "%s\n", c_ptr);
3796 fclose(fp);
3797
3798 ExecCmdsFromTmp(tmp_fname);
3799
3800 unlink(tmp_fname);
3801
3802 return TRUE;
3803 }
3804
HandleDoubleByteUTF8Chars(s,has_ch)3805 int HandleDoubleByteUTF8Chars(s, has_ch)
3806 char *s;
3807 int has_ch;
3808 {
3809 if (has_ch >= 2 && !canvasFontDoubleByte &&
3810 Tgim_has_stringprep_convert()) {
3811 char *psz=NULL, *psz1=NULL, *psz2=NULL, *psz_encoding=NULL;
3812 char buf[MAXSTRING];
3813
3814 GetCurFontInfoStr(buf, sizeof(buf));
3815 psz1 = strrchr(buf, '-');
3816 if (psz1 != NULL) {
3817 *psz1 = '\0';
3818 psz2 = strrchr(buf, '-');
3819 if (psz2 != NULL) {
3820 *psz2 = '\0';
3821 }
3822 *psz1 = '-';
3823 }
3824 if (psz2 != NULL) {
3825 if (strchr(&psz2[1], '*') == NULL) {
3826 psz_encoding = &psz2[1];
3827 }
3828 *psz2 = '-';
3829 }
3830 if (psz_encoding != NULL) {
3831 psz = Tgim_stringprep_convert(s, psz_encoding, "utf-8");
3832 if (psz != NULL && strlen(psz) == 1) {
3833 s[0] = psz[0];
3834 s[1] = '\0';
3835 has_ch = 1;
3836 }
3837 UtilFree(psz);
3838 }
3839 if (has_ch > 1) {
3840 s[0] = '\0';
3841 has_ch = 0;
3842 }
3843 }
3844 return has_ch;
3845 }
3846
3847 static XComposeStatus c_stat;
3848
DrawText(input)3849 void DrawText(input)
3850 XEvent *input;
3851 {
3852 if (input->type == ButtonPress) {
3853 HandleButton(&(input->xbutton));
3854 } else if (input->type == PropertyNotify) {
3855 if (gnInputMethod != TGIM_NONE) {
3856 char *psz_buf=NULL;
3857 XPropertyEvent *prop_ev=((XPropertyEvent*)input);
3858
3859 if (tgIMConvertProperty(mainDisplay, drawWindow, prop_ev, &psz_buf) &&
3860 psz_buf != NULL) {
3861 HandleInputFromBuffer(psz_buf);
3862 free(psz_buf);
3863 }
3864 }
3865 } else if (input->type == KeyPress) {
3866 char s[80];
3867 int has_ch=0;
3868 XKeyEvent *key_ev=NULL;
3869 KeySym key_sym=(KeySym)0;
3870
3871 if (!textCursorShown) return;
3872
3873 if (pasteInDrawTextMode) {
3874 pasteInDrawTextMode = FALSE;
3875 HandlePasteInDrawTextMode();
3876 return;
3877 } else if (copyInDrawTextMode) {
3878 copyInDrawTextMode = FALSE;
3879 HandleCopyInDrawTextMode();
3880 return;
3881 }
3882 key_ev = (&(input->xkey));
3883 if (gnInputMethod != TGIM_NONE &&
3884 /*
3885 * Cannot call: InputMethodTypeMatched(canvasFontDoubleByte) &&
3886 */
3887 tgIMExpectLookupString(mainDisplay, drawWindow)) {
3888 if (tgIMHandleLookupString(mainDisplay, drawWindow, key_ev,
3889 s, sizeof(s), &key_sym, &has_ch)) {
3890 if (has_ch > 0) s[has_ch] = '\0';
3891 has_ch = HandleDoubleByteUTF8Chars(s, has_ch);
3892 }
3893 TranslateKeys(s, &key_sym);
3894 } else {
3895 has_ch = XLookupString(key_ev, s, sizeof(s), &key_sym, &c_stat);
3896 if (has_ch > 0) s[has_ch] = '\0';
3897 if (gnInputMethod != TGIM_NONE) {
3898 char s1[80];
3899
3900 *s1 = '\0';
3901 if (tgIMTranslateKeyEvent(mainDisplay, mainWindow, key_ev, s1)) {
3902 strcpy(s, s1);
3903 /* added by Ambrose Li <acli@mingpaoxpress.com> */
3904 key_sym = (KeySym)0;
3905 }
3906 if (tgIMExpectClientMessage(mainDisplay, mainWindow)) {
3907 /* input characters only come from ClientMessage */
3908 return;
3909 }
3910 } else {
3911 TranslateKeys(s, &key_sym);
3912 }
3913 }
3914 if (HandleFunctionKey(key_sym)) {
3915 return;
3916 }
3917 if (textHighlight) {
3918 if (!CanCopyHighLightedTextAsUTF8Strings(NULL)) {
3919 ClearCopyUTF8Info();
3920 } else if (gstCopyUTF8Info.double_byte_valid &&
3921 !gstCopyUTF8Info.single_byte_valid) {
3922 CalcSingleByteInfoForCopyUTF8(NULL);
3923 }
3924 }
3925 HandleTextFromBuffer(key_ev, s, key_sym, has_ch);
3926 }
3927 }
3928
InsertHexOctalChar()3929 void InsertHexOctalChar()
3930 {
3931 XKeyEvent key_ev;
3932 KeySym key_sym=(KeySym)XK_Insert;
3933 char s[1];
3934 int has_ch=FALSE;
3935
3936 if (curChoice != DRAWTEXT || !textCursorShown) return;
3937
3938 memset(&key_ev, 0, sizeof(XKeyEvent));
3939 key_ev.state = (ControlMask | ShiftMask);
3940 s[0] = '\0';
3941 HandleTextFromBuffer(&key_ev, s, key_sym, has_ch);
3942 }
3943
InsertSymbol()3944 void InsertSymbol()
3945 {
3946 int need_to_restore=FALSE;
3947
3948 if (curChoice != DRAWTEXT || !textCursorShown) return;
3949
3950 if (textHighlight) {
3951 curTextModified = TRUE;
3952 DeleteHighlightedText();
3953 EndChangeCurText(FALSE);
3954 }
3955 if (curFont != FONT_SYM) {
3956 PushCurFont();
3957 need_to_restore = TRUE;
3958 }
3959 if (ChangeFont(FONT_SYM, FALSE)) {
3960 TgInsertSymbol_HandleCntrlSpace(mainDisplay, drawWindow);
3961 }
3962 if (need_to_restore) {
3963 PopCurFont();
3964 ChangeFont(curFont, FALSE);
3965 }
3966 }
3967
EditTextInAttr(attr_ptr)3968 void EditTextInAttr(attr_ptr)
3969 struct AttrRec *attr_ptr;
3970 {
3971 struct ObjRec *obj_ptr=attr_ptr->obj;
3972 int abs_x, abs_y, x_off=0, y_off=0;
3973 int ok=TRUE;
3974 int saved_grouped_text_editable=groupedTextEditable;
3975
3976 SetCurChoice(DRAWTEXT);
3977 if (obj_ptr->ctm == NULL) {
3978 abs_x = obj_ptr->obbox.ltx;
3979 abs_y = obj_ptr->obbox.lty;
3980 } else {
3981 abs_x = ((obj_ptr->obbox.ltx+obj_ptr->obbox.rbx)>>1);
3982 abs_y = ((obj_ptr->obbox.lty+obj_ptr->obbox.rby)>>1);
3983 }
3984 groupedTextEditable = TRUE;
3985 ok = (FindTextObj(OFFSET_X(abs_x), OFFSET_Y(abs_y), obj_ptr) == obj_ptr);
3986 groupedTextEditable = saved_grouped_text_editable;
3987 if (!ok) {
3988 return;
3989 }
3990 editingText = FALSE;
3991 curTextModified = FALSE;
3992
3993 if (!PrepareEditExistingText(obj_ptr, abs_x, abs_y, &x_off, &y_off)) {
3994 return;
3995 }
3996 textJustClicked = FALSE;
3997 if (curStrBlock != NULL) UpdateHighLightedTextBBoxes(TRUE);
3998 HandleClickOnText(FALSE, TRUE, x_off, y_off, FALSE, curTextObj, FALSE, TRUE,
3999 FALSE, (Time)0);
4000 RedrawCurText();
4001 UpdateTextInfoChoices(TRUE);
4002 }
4003
DumpOneStr(FP,FontIndex,DoubleByte,DoubleByteModBytes,Str)4004 void DumpOneStr(FP, FontIndex, DoubleByte, DoubleByteModBytes, Str)
4005 register FILE *FP;
4006 int FontIndex, DoubleByte, DoubleByteModBytes;
4007 register char *Str;
4008 {
4009 register char *c_ptr;
4010
4011 if (DoubleByte) {
4012 for ( ; *Str != '\0'; Str++) {
4013 switch (*Str) {
4014 case '(':
4015 case ')':
4016 case '\\': if (fprintf(FP, "\\") == EOF) writeFileFailed = TRUE; break;
4017 }
4018 if (((*Str) & 0x80) != '\0') {
4019 if (DoubleByteModBytes) {
4020 if (fprintf(FP, "\\%03o\\%03o", Str[0]&0x7f, Str[1]&0x7f) == EOF) {
4021 writeFileFailed = TRUE;
4022 }
4023 } else {
4024 #ifdef _PS_SEVENBIT_DOUBLEBYTE_TEXT
4025 if (fprintf(FP, "\\%03o\\%03o", Str[0]&0x7f, Str[1]&0x7f) == EOF) {
4026 #else /* ~_PS_SEVENBIT_DOUBLEBYTE_TEXT */
4027 if (fprintf(FP, "\\%03o\\%03o", Str[0]&0xff, Str[1]&0xff) == EOF) {
4028 #endif /* _PS_SEVENBIT_DOUBLEBYTE_TEXT */
4029 writeFileFailed = TRUE;
4030 }
4031 }
4032 Str++;
4033 if (*Str == '\0') break;
4034 } else {
4035 if (fprintf(FP, "%c", *Str) == EOF) writeFileFailed = TRUE;
4036 }
4037 }
4038 } else {
4039 for ( ; *Str != '\0'; Str++) {
4040 switch (*Str) {
4041 case '(':
4042 case ')':
4043 case '\\': fprintf(FP, "\\"); break;
4044 }
4045 if (((*Str) & 0x80) != '\0') {
4046 if (FontIndex != FONT_SYM &&
4047 (c_ptr=CharCodeTranslate(Str)) != NULL) {
4048 if (*c_ptr == '\\') {
4049 if (fprintf(FP, "%s", c_ptr) == EOF) writeFileFailed = TRUE;
4050 } else if (*c_ptr == '8') {
4051 if (fprintf(FP, "\\%c%c%c", c_ptr[2], c_ptr[3], c_ptr[4]) ==
4052 EOF) {
4053 writeFileFailed = TRUE;
4054 }
4055 }
4056 } else {
4057 if (fprintf(FP, "\\%o", (*Str)&0xff) == EOF) {
4058 writeFileFailed = TRUE;
4059 }
4060 }
4061 } else {
4062 if (fprintf(FP, "%c", *Str)== EOF) writeFileFailed = TRUE;
4063 }
4064 }
4065 }
4066 }
4067
DrawTextObj(Win,XOff,YOff,ObjPtr)4068 void DrawTextObj(Win, XOff, YOff, ObjPtr)
4069 Window Win;
4070 int XOff, YOff;
4071 struct ObjRec *ObjPtr;
4072 {
4073 struct TextRec *text_ptr=ObjPtr->detail.t;
4074 int x, y, xinc=0, yinc=0, trans_pat=0, fill=0, pen=0;
4075 int use_cache=FALSE;
4076 XGCValues values;
4077
4078 if (userDisableRedraw) return;
4079
4080 if ((text_ptr->fill == NONEPAT ||
4081 (ObjPtr->trans_pat && text_ptr->fill == BACKPAT)) &&
4082 (text_ptr->pen == NONEPAT ||
4083 (ObjPtr->trans_pat && text_ptr->pen == BACKPAT))) {
4084 return;
4085 }
4086 if (BlankMiniLines(&text_ptr->minilines)) {
4087 return;
4088 }
4089
4090 PushCurFont();
4091 ObjFontInfoToCurFontInfo(text_ptr);
4092 pen = text_ptr->pen;
4093
4094 if (NeedsToCacheTextObj(ObjPtr)) {
4095 if (text_ptr->cached_bitmap == None) {
4096 MakeCachedTextBitmap(ObjPtr);
4097 }
4098 use_cache = TRUE;
4099 }
4100 x = ObjPtr->x - XOff;
4101 y = ObjPtr->y - YOff;
4102
4103 xinc = 0;
4104 yinc = textCursorH+textVSpace;
4105
4106 trans_pat = ObjPtr->trans_pat;
4107 fill = text_ptr->fill;
4108
4109 if (curChoice == DRAWTEXT && textCursorShown && ObjPtr == curTextObj) {
4110 if (RestoreEditTextSize(ObjPtr, TRUE)) {
4111 UpdTextBBox(ObjPtr);
4112 }
4113 }
4114 if (fill != NONEPAT) {
4115 int real_x_off, real_y_off, ltx, lty, rbx, rby;
4116
4117 real_x_off = (zoomedIn ? XOff : (XOff>>zoomScale)<<zoomScale);
4118 real_y_off = (zoomedIn ? YOff : (YOff>>zoomScale)<<zoomScale);
4119 ltx = ZOOMED_SIZE(ObjPtr->bbox.ltx + 1 - real_x_off);
4120 lty = ZOOMED_SIZE(ObjPtr->bbox.lty + 1 - real_y_off);
4121 rbx = ZOOMED_SIZE(ObjPtr->bbox.rbx - 1 - real_x_off);
4122 rby = ZOOMED_SIZE(ObjPtr->bbox.rby - 1 - real_y_off);
4123
4124 values.foreground = GetDrawingBgPixel(fill, colorPixels[ObjPtr->color]);
4125 values.function = GXcopy;
4126 values.fill_style = (trans_pat ? FillStippled : FillOpaqueStippled);
4127 values.stipple = patPixmap[fill];
4128 XChangeGC(mainDisplay, drawGC,
4129 GCForeground | GCFunction | GCFillStyle | GCStipple, &values);
4130 if (ObjPtr->ctm != NULL) {
4131 XFillPolygon(mainDisplay, Win, drawGC, ObjPtr->rotated_obbox, 5,
4132 Convex, CoordModeOrigin);
4133 } else {
4134 XFillRectangle(mainDisplay, Win, drawGC, ltx, lty, rbx-ltx, rby-lty);
4135 }
4136 }
4137 if (pen == NONEPAT || (trans_pat && pen == BACKPAT)) {
4138 } else if (use_cache || ObjPtr->ctm != NULL || zoomScale != 0 ||
4139 text_ptr->read_only) {
4140 if (ObjPtr->obbox.ltx != ObjPtr->obbox.rbx &&
4141 ObjPtr->obbox.lty != ObjPtr->obbox.rby) {
4142 int ltx, lty, w, h;
4143
4144 ltx = OFFSET_X(ObjPtr->bbox.ltx+1);
4145 lty = OFFSET_Y(ObjPtr->bbox.lty+1);
4146 w = ZOOMED_SIZE(ObjPtr->bbox.rbx-ObjPtr->bbox.ltx-2);
4147 h = ZOOMED_SIZE(ObjPtr->bbox.rby-ObjPtr->bbox.lty-2);
4148
4149 if (!trans_pat) {
4150 values.foreground = myBgPixel;
4151 values.function = GXcopy;
4152 values.fill_style = FillSolid;
4153 values.clip_mask = text_ptr->cached_bg_bitmap;
4154 values.clip_x_origin = ltx;
4155 values.clip_y_origin = lty;
4156 XChangeGC(mainDisplay, drawGC,
4157 GCForeground | GCFunction | GCFillStyle | GCClipMask |
4158 GCClipXOrigin | GCClipYOrigin, &values);
4159 FillClippedRectangle(Win, drawGC, ltx, lty, w, h);
4160 }
4161 values.function = GXcopy;
4162 values.fill_style = (trans_pat ? FillStippled : FillOpaqueStippled);
4163 values.stipple = patPixmap[pen];
4164 values.clip_mask = text_ptr->cached_bitmap;
4165 values.clip_x_origin = ltx;
4166 values.clip_y_origin = lty;
4167 XChangeGC(mainDisplay, drawGC,
4168 GCFunction | GCFillStyle | GCStipple | GCClipMask |
4169 GCClipXOrigin | GCClipYOrigin, &values);
4170
4171 DrawClippedPixmap(text_ptr->cached_pixmap, Win, drawGC, w, h,
4172 ltx, lty);
4173
4174 values.clip_mask = None;
4175 values.clip_x_origin = 0;
4176 values.clip_y_origin = 0;
4177 XChangeGC(mainDisplay, drawGC,
4178 GCClipMask | GCClipXOrigin | GCClipYOrigin, &values);
4179 if (numClipRecs > 0) {
4180 XSetClipRectangles(mainDisplay, drawGC, 0, 0, clipRecs,
4181 numClipRecs, clipOrdering);
4182 }
4183 }
4184 } else {
4185 MiniLinesInfo *minilines=(&text_ptr->minilines);
4186 int saved_pen=penPat, saved_trans_pat=transPat;
4187 int baseline_y=text_ptr->baseline_y-YOff;
4188
4189 ResetDirtyBBoxInfo();
4190 penPat = pen;
4191 transPat = trans_pat;
4192 PaintMiniLines(mainDisplay, Win, drawGC, mainDepth, x, baseline_y,
4193 minilines, FALSE, FALSE);
4194 penPat = saved_pen;
4195 transPat = saved_trans_pat;
4196 }
4197 if (curChoice == DRAWTEXT && textCursorShown && ObjPtr == curTextObj) {
4198 if (RestoreEditTextSize(ObjPtr, FALSE)) {
4199 UpdTextBBox(ObjPtr);
4200 }
4201 }
4202 PopCurFont();
4203 }
4204
4205 #define FONTS_PER_DPI (((MAXFONTS-1)*MAXFONTSTYLES+1)*MAXFONTSIZES)
4206
4207 static
OldFontIndex(dpi_index,font_index,size_index,style_index)4208 int OldFontIndex(dpi_index, font_index, size_index, style_index)
4209 register int dpi_index, font_index, size_index, style_index;
4210 /* obsoleted procedure, kept to remain compatible with old versions */
4211 {
4212 if (font_index == FONT_SYM) {
4213 return (size_index+MAXFONTSIZES*(MAXFONTSTYLES*font_index) +
4214 dpi_index*FONTS_PER_DPI);
4215 } else {
4216 return (size_index+MAXFONTSIZES*(style_index+MAXFONTSTYLES*font_index) +
4217 dpi_index*FONTS_PER_DPI);
4218 }
4219 }
4220
4221 static
ReadTextSetFontStyleSzUnit(font_str,sb_font_str,style,sz_unit,size,dpi,pn_double_byte,pn_cur_sb_font,pn_cur_db_font)4222 void ReadTextSetFontStyleSzUnit(font_str, sb_font_str, style, sz_unit,
4223 size, dpi, pn_double_byte, pn_cur_sb_font, pn_cur_db_font)
4224 char *font_str, *sb_font_str;
4225 int style, sz_unit, size, dpi;
4226 int *pn_double_byte, *pn_cur_sb_font, *pn_cur_db_font;
4227 /*
4228 * set curFont, curStyle, and curSzUnit
4229 */
4230 {
4231 char *psz=NULL;
4232 int len=strlen(font_str);
4233
4234 if (len > 1 && *font_str == '\'' && font_str[len-1] == '\'') {
4235 char *psz1=(&font_str[1]);
4236
4237 font_str[len-1] = '\0';
4238 psz = font_str;
4239 while (*psz1 != '\0') *psz++ = *psz1++;
4240 *psz = '\0';
4241 }
4242 if (fileVersion <= 33 && (psz=strchr(font_str, '%')) != NULL) {
4243 *pn_double_byte = TRUE;
4244 }
4245 if (*pn_double_byte) {
4246 if ((psz=strchr(font_str, '%')) != NULL) {
4247 *psz++ = '\0';
4248 strcpy(sb_font_str, font_str);
4249 strcpy(font_str, psz);
4250 /*
4251 * e.g., font_str="Ryumin-Light-EUC-H", sb_font_str="Helvetica-Bold"
4252 */
4253 }
4254 }
4255 /*
4256 * Set curFont and cur_sb_font so that they correspond to the text object.
4257 */
4258 if (PRTGIF && !cmdLineOpenDisplay) {
4259 curFont = GetFontIndex(font_str, style, FALSE);
4260 if (*pn_double_byte) {
4261 *pn_cur_db_font = curFont;
4262 *pn_cur_sb_font = GetFontIndex(sb_font_str, style, FALSE);
4263 }
4264 } else {
4265 curFont = GetFontIndex(font_str, style, TRUE);
4266 if (curFont == INVALID) {
4267 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_FIND_FONT_USE_ALT),
4268 font_str, "Times");
4269 Msg(gszMsgBox);
4270 SetFileModified(TRUE);
4271 curFont = FONT_TIM;
4272 if (*pn_double_byte) {
4273 /*
4274 * curFont would have been the double-byte font.
4275 * But since it can't be found and Times is used, it should
4276 * not be double-byte any more.
4277 */
4278 *pn_double_byte = FALSE;
4279 }
4280 }
4281 if (*pn_double_byte) {
4282 *pn_cur_db_font = curFont;
4283 *pn_cur_sb_font = GetFontIndex(sb_font_str, style, TRUE);
4284 if (*pn_cur_sb_font == INVALID) {
4285 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_FIND_FONT_USE_ALT),
4286 sb_font_str, "Times");
4287 Msg(gszMsgBox);
4288 SetFileModified(TRUE);
4289 *pn_cur_sb_font = FONT_TIM;
4290 }
4291 }
4292 }
4293 curStyle = style;
4294 if (fileVersion <= 29) {
4295 size = GetCompatibleSize(dpi, size);
4296 }
4297 if (fileVersion <= 35) {
4298 curSzUnit = FontSizeToSzUnit(size);
4299 } else {
4300 curSzUnit = sz_unit;
4301 }
4302 }
4303
4304 static
ReadTextSetCanvasFont(text_ptr,dpi,size,asc,des,double_byte,db_mod_bytes,db_vertical,direction)4305 void ReadTextSetCanvasFont(text_ptr, dpi, size, asc, des, double_byte,
4306 db_mod_bytes, db_vertical, direction)
4307 struct TextRec *text_ptr;
4308 int dpi, size, asc, des, double_byte, db_mod_bytes, db_vertical, direction;
4309 /*
4310 * set canvasFontAsc, canvasFontDes, textCursorH, and canvasFontDoubleByte...
4311 */
4312 {
4313 if (PRTGIF) {
4314 if (fileVersion < 10) {
4315 canvasFontAsc =
4316 pDrawFontAsc[OldFontIndex(dpi,curFont,size,curStyle)];
4317 canvasFontDes =
4318 pDrawFontDes[OldFontIndex(dpi,curFont,size,curStyle)];
4319 } else {
4320 canvasFontAsc = asc;
4321 canvasFontDes = des;
4322 }
4323 textCursorH = canvasFontAsc + canvasFontDes;
4324 text_ptr->read_only = FALSE;
4325 if (fileVersion > 31) {
4326 canvasFontDoubleByte = double_byte;
4327 canvasFontDirection = direction;
4328 /*
4329 * Need to fix this in the future.
4330 */
4331 canvasFontDontReencode = FALSE;
4332
4333 canvasFontDoubleByteModBytes = db_mod_bytes;
4334 canvasFontDoubleByteVertical = db_vertical;
4335 } else {
4336 canvasFontDoubleByte = FALSE;
4337 canvasFontDoubleByteModBytes = FALSE;
4338 canvasFontDoubleByteVertical = FALSE;
4339 canvasFontDirection = FontLeftToRight;
4340 canvasFontDontReencode = FALSE;
4341 }
4342 } else {
4343 /*
4344 * since fileVersion 37 there's no such a thing as a read_only
4345 * text object. If after SetCanvasFont() and
4346 * canvasFontSize != INVALID &&
4347 * SzUnitToFontSize(curSzUnit) != canvasFontSize
4348 */
4349 if (fileVersion <= 36) {
4350 text_ptr->read_only = SetCanvasFont();
4351 } else {
4352 /* curFont, curStyle, and curSzUnit are undefined here */
4353 }
4354 }
4355 }
4356
4357 static
ReadStrSeg(FP,ppStrSeg)4358 int ReadStrSeg(FP, ppStrSeg)
4359 FILE *FP;
4360 StrSegInfo **ppStrSeg;
4361 {
4362 int font=0, style=0, sz_unit=0;
4363 int w=0, asc=0, des=0, min_lbearing=0, max_rextra=0;
4364 int underline_on=0, direction=0, new_alloc=FALSE, modified=FALSE;
4365 int double_byte=0, db_mod_bytes=0, db_vertical=0, dontreencode=FALSE;
4366 char *s=NULL, *line=NULL, color_str[40], font_str[MAXSTRING], *psz=NULL;
4367 StrSegInfo *pStrSeg=NULL;
4368
4369 *font_str = '\0';
4370 *ppStrSeg = NULL;
4371 if ((line=UtilGetALine(FP)) == NULL) {
4372 sprintf(gszMsgBox, TgLoadString(STID_UNEXPECTED_EOF_IN_ABORT_READ),
4373 scanFileName, scanLineNum, "ReadStrSeg()");
4374 if (PRTGIF) {
4375 fprintf(stderr, "%s\n", gszMsgBox);
4376 } else {
4377 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4378 }
4379 return FALSE;
4380 }
4381 scanLineNum++;
4382
4383 s = FindChar((int)'(', line);
4384 s = ParseStr(s, (int)',', color_str, sizeof(color_str));
4385 InitScan(s, ", \t\n");
4386
4387 if (fileVersion >= 37) {
4388 if (GETSTR("str_seg", font_str, "font_str") == INVALID ||
4389 GETINT("str_seg", style, "style") == INVALID ||
4390 GETINT("str_seg", sz_unit, "sz_unit") == INVALID ||
4391 GETINT("str_seg", w, "w") == INVALID ||
4392 GETINT("str_seg", asc, "asc") == INVALID ||
4393 GETINT("str_seg", des, "des") == INVALID ||
4394 GETINT("str_seg", min_lbearing, "min_lbearing") == INVALID ||
4395 GETINT("str_seg", max_rextra, "max_rextra") == INVALID ||
4396 GETINT("str_seg", underline_on, "underline_on") == INVALID ||
4397 GETINT("str_seg", double_byte, "double_byte") == INVALID ||
4398 GETINT("str_seg", db_mod_bytes, "db_mod_bytes") == INVALID ||
4399 GETINT("str_seg", db_vertical, "db_vertical") == INVALID ||
4400 GETINT("str_seg", direction, "direction") == INVALID) {
4401 return FALSE;
4402 }
4403 }
4404 free(line);
4405
4406 font = GetFontIndexFromPSFontAndStyle(font_str, style, &double_byte,
4407 &modified);
4408 if (modified) SetFileModified(TRUE);
4409
4410 if ((line=UtilGetALine(FP)) == NULL) {
4411 sprintf(gszMsgBox, TgLoadString(STID_UNEXPECTED_EOF_IN_ABORT_READ),
4412 scanFileName, scanLineNum, "ReadStrSeg()");
4413 if (PRTGIF) {
4414 fprintf(stderr, "%s\n", gszMsgBox);
4415 } else {
4416 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4417 }
4418 return FALSE;
4419 }
4420 scanLineNum++;
4421
4422 psz = FindChar((int)'"', line);
4423 s = ReadString(psz);
4424 *(--s) = '\0';
4425
4426 pStrSeg = NewStrSeg();
4427 DynStrSet(&pStrSeg->dyn_str, psz);
4428
4429 free(line);
4430
4431 pStrSeg->color = QuickFindColorIndex(NULL, color_str, &new_alloc, TRUE);
4432 UtilStrCpyN(pStrSeg->color_str, sizeof(pStrSeg->color_str), color_str);
4433
4434 if (PRTGIF) {
4435 if (*font_str != '\0') {
4436 pStrSeg->font_name = UtilStrDup(font_str);
4437 if (pStrSeg->font_name == NULL) FailAllocMessage();
4438 }
4439 } else {
4440 curFont = font;
4441 curStyle = style;
4442 curSzUnit = sz_unit;
4443 SetCanvasFont();
4444 if (canvasFontSize != INVALID &&
4445 SzUnitToFontSize(curSzUnit) != canvasFontSize) {
4446 SetFileModified(TRUE);
4447 sz_unit = curSzUnit = FontSizeToSzUnit(canvasFontSize);
4448 }
4449 double_byte = canvasFontDoubleByte;
4450 db_mod_bytes = canvasFontDoubleByteModBytes;
4451 db_vertical = canvasFontDoubleByteVertical;
4452 direction = canvasFontDirection;
4453 dontreencode = canvasFontDontReencode;
4454 }
4455 pStrSeg->font = font;
4456 pStrSeg->style = style;
4457 pStrSeg->sz_unit = sz_unit;
4458 pStrSeg->w = w;
4459 pStrSeg->asc = asc;
4460 pStrSeg->des = des;
4461 pStrSeg->min_lbearing = min_lbearing;
4462 pStrSeg->max_rextra = max_rextra;
4463
4464 pStrSeg->underline_on = (underline_on & 0x1);
4465 pStrSeg->overline_on = ((underline_on & 0x2) == 0x2);
4466 pStrSeg->double_byte = double_byte;
4467 pStrSeg->double_byte_mod_bytes = db_mod_bytes;
4468 pStrSeg->double_byte_vertical = db_vertical;
4469 pStrSeg->direction = direction;
4470 pStrSeg->dontreencode = dontreencode;
4471
4472 *ppStrSeg = pStrSeg;
4473
4474 return TRUE;
4475 }
4476
4477 static
ReadStrBlock(FP,pOwnerMiniLine,ppStrBlock)4478 int ReadStrBlock(FP, pOwnerMiniLine, ppStrBlock)
4479 FILE *FP;
4480 MiniLineInfo *pOwnerMiniLine;
4481 StrBlockInfo **ppStrBlock;
4482 {
4483 int type=INVALID, w=0, asc=0, des=0, min_lbearing=0, max_rextra=0;
4484 int special_char_w=0, has_sup=0, has_sub=0;
4485 char *s=NULL, *line=NULL;
4486 StrBlockInfo *pStrBlock=NULL;
4487 StrSegInfo *pStrSeg=NULL;
4488 MiniLinesInfo *minilines=NULL;
4489
4490 *ppStrBlock = NULL;
4491 if ((line=UtilGetALine(FP)) == NULL) {
4492 sprintf(gszMsgBox, TgLoadString(STID_UNEXPECTED_EOF_IN_ABORT_READ),
4493 scanFileName, scanLineNum, "ReadStrBlock()");
4494 if (PRTGIF) {
4495 fprintf(stderr, "%s\n", gszMsgBox);
4496 } else {
4497 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4498 }
4499 return FALSE;
4500 }
4501 scanLineNum++;
4502
4503 if (*line == ']') {
4504 free(line);
4505 return TRUE;
4506 }
4507 s = FindChar((int)'(', line);
4508 InitScan(s, ", \t\n");
4509
4510 if (fileVersion >= 37) {
4511 if (GETINT("str_block", type, "type") == INVALID ||
4512 GETINT("str_block", w, "w") == INVALID ||
4513 GETINT("str_block", asc, "asc") == INVALID ||
4514 GETINT("str_block", des, "des") == INVALID ||
4515 GETINT("str_block", min_lbearing, "min_lbearing") == INVALID ||
4516 GETINT("str_block", max_rextra, "max_rextra") == INVALID ||
4517 GETINT("str_block", special_char_w, "special_char_w") == INVALID ||
4518 GETINT("str_block", has_sup, "has_sup") == INVALID ||
4519 GETINT("str_block", has_sub, "has_sub") == INVALID) {
4520 return FALSE;
4521 }
4522 }
4523 pStrBlock = NewStrBlock();
4524 pStrBlock->type = type;
4525 pStrBlock->w = w;
4526 pStrBlock->asc = asc;
4527 pStrBlock->des = des;
4528 pStrBlock->min_lbearing = min_lbearing;
4529 pStrBlock->max_rextra = max_rextra;
4530 pStrBlock->special_char_w = special_char_w;
4531
4532 free(line);
4533
4534 switch (type) {
4535 case SB_SIMPLE:
4536 pStrSeg = NULL;
4537 if (!ReadStrSeg(FP, &pStrSeg)) {
4538 return FALSE;
4539 }
4540 pStrBlock->seg = pStrSeg;
4541 break;
4542
4543 case SB_CHAR_SPACE: break;
4544
4545 case SB_SUPSUB_LEFT:
4546 case SB_SUPSUB_CENTER:
4547 case SB_SUPSUB_RIGHT:
4548 if (has_sup) {
4549 minilines = NULL;
4550 if (!ReadMiniLines(FP, pStrBlock, &minilines) || minilines == NULL) {
4551 return FALSE;
4552 }
4553 pStrBlock->sup = minilines;
4554 }
4555 if (has_sub) {
4556 minilines = NULL;
4557 if (!ReadMiniLines(FP, pStrBlock, &minilines) || minilines == NULL) {
4558 return FALSE;
4559 }
4560 pStrBlock->sub = minilines;
4561 }
4562 if (type == SB_SUPSUB_CENTER) {
4563 pStrSeg = NULL;
4564 if (!ReadStrSeg(FP, &pStrSeg)) {
4565 return FALSE;
4566 }
4567 pStrBlock->seg = pStrSeg;
4568 }
4569 if ((line=UtilGetALine(FP)) == NULL) {
4570 sprintf(gszMsgBox, TgLoadString(STID_UNEXPECTED_EOF_IN_ABORT_READ),
4571 scanFileName, scanLineNum, "ReadStrBlock()");
4572 if (PRTGIF) {
4573 fprintf(stderr, "%s\n", gszMsgBox);
4574 } else {
4575 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4576 }
4577 return FALSE;
4578 }
4579 scanLineNum++;
4580
4581 if (*line != ']') {
4582 sprintf(gszMsgBox, TgLoadString(STID_UNEXPECTED_TOK_IN_ABORT_READ),
4583 scanFileName, scanLineNum, ']', "ReadStrBlock()");
4584 if (PRTGIF) {
4585 fprintf(stderr, "%s\n", gszMsgBox);
4586 } else {
4587 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4588 }
4589 return FALSE;
4590 }
4591 free(line);
4592 break;
4593 }
4594 pStrBlock->owner_mini_line = pOwnerMiniLine;
4595
4596 *ppStrBlock = pStrBlock;
4597
4598 return TRUE;
4599 }
4600
4601 static
ReadMiniLine(FP,pOwnerMiniLines,ppMiniLine)4602 int ReadMiniLine(FP, pOwnerMiniLines, ppMiniLine)
4603 FILE *FP;
4604 MiniLinesInfo *pOwnerMiniLines;
4605 MiniLineInfo **ppMiniLine;
4606 {
4607 int w=0, asc=0, des=0, min_lbearing=0, max_rextra=0, v_gap=0;
4608 char *s=NULL, *line=NULL;
4609 MiniLineInfo *pMiniLine=NULL;
4610 StrBlockInfo *pFirstStrBlock=NULL, *pLastStrBlock=NULL;
4611
4612 *ppMiniLine = NULL;
4613 if ((line=UtilGetALine(FP)) == NULL) {
4614 sprintf(gszMsgBox, TgLoadString(STID_UNEXPECTED_EOF_IN_ABORT_READ),
4615 scanFileName, scanLineNum, "ReadMiniLine()");
4616 if (PRTGIF) {
4617 fprintf(stderr, "%s\n", gszMsgBox);
4618 } else {
4619 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4620 }
4621 return FALSE;
4622 }
4623 scanLineNum++;
4624
4625 if (*line == ']') {
4626 free(line);
4627 return TRUE;
4628 }
4629 s = FindChar((int)'(', line);
4630 InitScan(s, ", \t\n");
4631
4632 if (fileVersion >= 37) {
4633 if (GETINT("mini_line", w, "w") == INVALID ||
4634 GETINT("mini_line", asc, "asc") == INVALID ||
4635 GETINT("mini_line", des, "des") == INVALID ||
4636 GETINT("mini_line", min_lbearing, "min_lbearing") == INVALID ||
4637 GETINT("mini_line", max_rextra, "max_rextra") == INVALID ||
4638 GETINT("mini_line", v_gap, "v_gap") == INVALID) {
4639 return FALSE;
4640 }
4641 }
4642 pMiniLine = NewMiniLine();
4643 pMiniLine->w = w;
4644 pMiniLine->asc = asc;
4645 pMiniLine->des = des;
4646 pMiniLine->min_lbearing = min_lbearing;
4647 pMiniLine->max_rextra = max_rextra;
4648 pMiniLine->v_gap = v_gap;
4649
4650 free(line);
4651
4652 for (;;) {
4653 StrBlockInfo *pStrBlock=NULL;
4654
4655 if (!ReadStrBlock(FP, pMiniLine, &pStrBlock)) {
4656 FreeStrBlockList(pFirstStrBlock);
4657 return FALSE;
4658 }
4659 if (pStrBlock == NULL) {
4660 /* shouldn't come here if num_lines is correct */
4661 break;
4662 }
4663 InsertStrBlock(pLastStrBlock, NULL, pStrBlock, &pFirstStrBlock,
4664 &pLastStrBlock);
4665 }
4666 pMiniLine->first_block = pFirstStrBlock;
4667 pMiniLine->last_block = pLastStrBlock;
4668 pMiniLine->owner_minilines = pOwnerMiniLines;
4669
4670 *ppMiniLine = pMiniLine;
4671
4672 return TRUE;
4673 }
4674
ReadMiniLines(FP,pOwnerBlock,ppMiniLines)4675 int ReadMiniLines(FP, pOwnerBlock, ppMiniLines)
4676 FILE *FP;
4677 StrBlockInfo *pOwnerBlock;
4678 MiniLinesInfo **ppMiniLines;
4679 {
4680 int w=0, h=0, min_lbearing=0, max_rextra=0;
4681 int just=0, v_space=0, baseline_offset=0;
4682 char *s=NULL, *line=NULL;
4683 MiniLinesInfo *minilines=NULL;
4684 MiniLineInfo *pFirstMiniLine=NULL, *pLastMiniLine=NULL;
4685
4686 *ppMiniLines = NULL;
4687 if ((line=UtilGetALine(FP)) == NULL) {
4688 sprintf(gszMsgBox, TgLoadString(STID_UNEXPECTED_EOF_IN_ABORT_READ),
4689 scanFileName, scanLineNum, "ReadMiniLines()");
4690 if (PRTGIF) {
4691 fprintf(stderr, "%s\n", gszMsgBox);
4692 } else {
4693 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4694 }
4695 return FALSE;
4696 }
4697 scanLineNum++;
4698
4699 s = FindChar((int)'(', line);
4700 InitScan(s, ", \t\n");
4701
4702 if (fileVersion >= 37) {
4703 if (GETINT("minilines", w, "w") == INVALID ||
4704 GETINT("minilines", h, "h") == INVALID ||
4705 GETINT("minilines", min_lbearing, "min_lbearing") == INVALID ||
4706 GETINT("minilines", max_rextra, "max_rextra") == INVALID ||
4707 GETINT("minilines", just, "just") == INVALID ||
4708 GETINT("minilines", v_space, "v_space") == INVALID ||
4709 GETINT("minilines", baseline_offset, "baseline_offset") == INVALID) {
4710 return FALSE;
4711 }
4712 }
4713 minilines = NewMiniLines();
4714 minilines->w = w;
4715 minilines->h = h;
4716 minilines->min_lbearing = min_lbearing;
4717 minilines->max_rextra = max_rextra;
4718 minilines->just = just;
4719 minilines->v_space = v_space;
4720 minilines->baseline_offset = baseline_offset;
4721
4722 free(line);
4723
4724 for (;;) {
4725 MiniLineInfo *pMiniLine=NULL;
4726
4727 if (!ReadMiniLine(FP, minilines, &pMiniLine)) {
4728 FreeMiniLineList(pFirstMiniLine);
4729 return FALSE;
4730 }
4731 if (pMiniLine == NULL) {
4732 /* shouldn't come here if num_lines is correct */
4733 break;
4734 }
4735 if (pMiniLine->first_block == NULL) {
4736 StrBlockInfo *pStrBlock=CreateStrBlockFromString("", pMiniLine);
4737
4738 pMiniLine->first_block = pMiniLine->last_block = pStrBlock;
4739 }
4740 InsertMiniLine(pLastMiniLine, NULL, pMiniLine, &pFirstMiniLine,
4741 &pLastMiniLine);
4742 }
4743 minilines->first = pFirstMiniLine;
4744 minilines->last = pLastMiniLine;
4745 minilines->owner_block = pOwnerBlock;
4746
4747 *ppMiniLines = minilines;
4748
4749 return TRUE;
4750 }
4751
4752 static
ReadTextLines(FP,ObjPtr,text_ptr,color_str,num_lines,has_ps_bitmap,cur_sb_font,cur_db_font,double_byte,db_mod_bytes,db_vertical,direction,x,baseline_y,text_w,pn_max_len,pn_max_h)4753 int ReadTextLines(FP, ObjPtr, text_ptr, color_str, num_lines, has_ps_bitmap,
4754 cur_sb_font, cur_db_font, double_byte, db_mod_bytes, db_vertical,
4755 direction, x, baseline_y, text_w, pn_max_len, pn_max_h)
4756 FILE *FP;
4757 struct ObjRec **ObjPtr;
4758 struct TextRec *text_ptr;
4759 char *color_str;
4760 int num_lines, has_ps_bitmap, cur_sb_font, cur_db_font;
4761 int double_byte, db_mod_bytes, db_vertical, direction;
4762 int x, baseline_y, *pn_max_len, *pn_max_h;
4763 /*
4764 * (Note: text_w is only used for fileVersion <= 36)
4765 */
4766 {
4767 int len=0;
4768
4769 /*
4770 * Set readingTextObject to TRUE to *enable* the setting of the read_only
4771 * fields in the string segments and the text object.
4772 */
4773 readingTextObject = TRUE;
4774 if (deserializingFile) ReadCreatorID(FP, ObjPtr);
4775 if (fileVersion <= 36) {
4776 int i=0, line_h=canvasFontAsc+canvasFontDes+textVSpace;
4777
4778 for (i=0; i < num_lines; i++) {
4779 int new_alloc=FALSE;
4780 char *tmp_str=NULL, *s=NULL, *line=NULL;
4781 MiniLineInfo *pMiniLine=NULL;
4782 StrSegInfo *pStrSeg=NULL;
4783 RecalcMetricsInfo rmi;
4784
4785 if ((line=UtilGetALine(FP)) == NULL) {
4786 sprintf(gszMsgBox, TgLoadString(STID_UNEXPECTED_EOF_IN_ABORT_READ),
4787 scanFileName, scanLineNum, "ReadTextLines()");
4788 if (PRTGIF) {
4789 fprintf(stderr, "%s\n", gszMsgBox);
4790 } else {
4791 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4792 }
4793 return FALSE;
4794 }
4795 scanLineNum++;
4796
4797 tmp_str = FindChar((int)'"', line);
4798 s = ReadString(tmp_str);
4799 *(--s) = '\0';
4800
4801 pMiniLine = NewMiniLine();
4802 if (double_byte) {
4803 /*
4804 * Note: should not get here for PRTGIF because
4805 * double_byte is always 0 in any released version
4806 * of tgif for fileVersion <= 36.
4807 */
4808 struct StrRec *pStr=NULL, *pStr1=NULL;
4809
4810 pStr = SegmentDoubleByteString(tmp_str);
4811 for (pStr1=pStr; pStr1 != NULL; pStr1=pStr1->next) {
4812 int str_seg_double_byte=((*pStr1->dyn_str.s) & 0x80);
4813 StrBlockInfo *pStrBlock=NewStrBlock();
4814
4815 pStrBlock->prev = pMiniLine->last_block;
4816 pStrBlock->next = NULL;
4817 if (pMiniLine->first_block == NULL) {
4818 pMiniLine->first_block = pStrBlock;
4819 } else {
4820 pMiniLine->last_block->next = pStrBlock;
4821 }
4822 pMiniLine->last_block = pStrBlock;
4823
4824 pStrBlock->type = SB_SIMPLE;
4825 pStrBlock->seg = pStrSeg = NewStrSeg();
4826 DynStrSet(&pStrSeg->dyn_str, pStr1->dyn_str.s);
4827
4828 pStrSeg->color = QuickFindColorIndex(NULL, color_str, &new_alloc,
4829 TRUE);
4830 UtilStrCpyN(pStrSeg->color_str, sizeof(pStrSeg->color_str),
4831 color_str);
4832
4833 curFont = (str_seg_double_byte ? cur_db_font : cur_sb_font);
4834 if (!PRTGIF) {
4835 SetCanvasFont();
4836 if (canvasFontSize != INVALID &&
4837 SzUnitToFontSize(curSzUnit) != canvasFontSize) {
4838 SetFileModified(TRUE);
4839 curSzUnit = FontSizeToSzUnit(canvasFontSize);
4840 }
4841 }
4842 pStrSeg->double_byte = canvasFontDoubleByte;
4843 pStrSeg->double_byte_mod_bytes = canvasFontDoubleByteModBytes;
4844 pStrSeg->double_byte_vertical = canvasFontDoubleByteVertical;
4845 pStrSeg->font = curFont;
4846 pStrSeg->style = curStyle;
4847 pStrSeg->sz_unit = curSzUnit;
4848 pStrSeg->direction = direction;
4849 pStrSeg->read_only = text_ptr->read_only;
4850 pStrSeg->orig_w = text_ptr->orig_w; /* valid if read_only */
4851 pStrSeg->orig_h = text_ptr->orig_h; /* valid if read_only */
4852 pStrSeg->underline_on = curUnderlineOn;
4853 pStrSeg->overline_on = curOverlineOn;
4854 pStrSeg->asc = canvasFontAsc;
4855 pStrSeg->des = canvasFontDes;
4856 /*
4857 * pStrSeg->w = text_w;
4858 *
4859 * Well, this doesn't really work here for PRTGIF. But since
4860 * double-byte for version <= 36 is really not supported,
4861 * (and the file does not contain enough information)
4862 * this bug really cannot be fixed.
4863 */
4864 }
4865 FreeStrList(pStr);
4866 } else {
4867 pMiniLine->first_block = pMiniLine->last_block = NewStrBlock();
4868 pMiniLine->first_block->type = SB_SIMPLE;
4869 pMiniLine->first_block->seg = pStrSeg = NewStrSeg();
4870 DynStrSet(&pStrSeg->dyn_str, tmp_str);
4871
4872 pStrSeg->color = QuickFindColorIndex(NULL, color_str, &new_alloc,
4873 TRUE);
4874 UtilStrCpyN(pStrSeg->color_str, sizeof(pStrSeg->color_str),
4875 color_str);
4876
4877 if (!PRTGIF) {
4878 SetCanvasFont();
4879 if (canvasFontSize != INVALID &&
4880 SzUnitToFontSize(curSzUnit) != canvasFontSize) {
4881 SetFileModified(TRUE);
4882 curSzUnit = FontSizeToSzUnit(canvasFontSize);
4883 }
4884 }
4885 pStrSeg->font = curFont;
4886 pStrSeg->style = curStyle;
4887 pStrSeg->sz_unit = curSzUnit;
4888 pStrSeg->direction = direction;
4889 pStrSeg->read_only = text_ptr->read_only;
4890 pStrSeg->orig_w = text_ptr->orig_w; /* valid if read_only */
4891 pStrSeg->orig_h = text_ptr->orig_h; /* valid if read_only */
4892 pStrSeg->underline_on = curUnderlineOn;
4893 pStrSeg->overline_on = curOverlineOn;
4894 pStrSeg->asc = canvasFontAsc;
4895 pStrSeg->des = canvasFontDes;
4896 pStrSeg->w = text_w;
4897 }
4898 memset(&rmi, 0, sizeof(RecalcMetricsInfo));
4899 rmi.x = rmi.orig_x = x;
4900 rmi.orig_baseline_y = text_ptr->baseline_y;
4901 rmi.baseline_y = baseline_y;
4902
4903 if (PRTGIF) {
4904 dontRecalcStrSegMetrics = TRUE;
4905 RecalcMiniLineMetrics(pMiniLine, &rmi);
4906 dontRecalcStrSegMetrics = FALSE;
4907 } else {
4908 PushCurFont();
4909 if (!RecalcMiniLineMetrics(pMiniLine, &rmi)) {
4910 text_ptr->read_only = TRUE;
4911 }
4912 PopCurFont();
4913 }
4914 InsertMiniLine(lastMiniLine, NULL, pMiniLine, &firstMiniLine,
4915 &lastMiniLine);
4916
4917 if (PRTGIF) {
4918 len = strlen(tmp_str); /* assume string width = 1 pixel per char */
4919 if (len > (*pn_max_len)) (*pn_max_len) = len;
4920 }
4921 baseline_y += line_h;
4922 free(line);
4923 }
4924 *pn_max_h = baseline_y - text_ptr->baseline_y;
4925 if (has_ps_bitmap) {
4926 sprintf(gszMsgBox, TgLoadString(STID_ILLEGAL_FIELD_IN_ABORT_READ),
4927 scanFileName, scanLineNum, "has_ps_bitmap", "ReadTextLines()");
4928 if (PRTGIF) {
4929 fprintf(stderr, "%s\n", gszMsgBox);
4930 } else {
4931 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4932 }
4933 return FALSE;
4934 }
4935 } else {
4936 MiniLinesInfo *minilines=NULL;
4937 MiniLineInfo *pMiniLine=NULL;
4938 int v_space=0;
4939
4940 PushCurFont();
4941 ReadMiniLines(FP, NULL, &minilines);
4942 PopCurFont();
4943 if (minilines == NULL) {
4944 return FALSE;
4945 }
4946 firstMiniLine = minilines->first;
4947 lastMiniLine = minilines->last;
4948 v_space = minilines->v_space;
4949 free(minilines);
4950
4951 for (pMiniLine=firstMiniLine; pMiniLine != NULL;
4952 pMiniLine=pMiniLine->next) {
4953 RecalcMetricsInfo rmi;
4954
4955 memset(&rmi, 0, sizeof(RecalcMetricsInfo));
4956 rmi.x = rmi.orig_x = x;
4957 rmi.orig_baseline_y = text_ptr->baseline_y;
4958 rmi.baseline_y = baseline_y;
4959
4960 if (PRTGIF) {
4961 dontRecalcStrSegMetrics = TRUE;
4962 RecalcMiniLineMetrics(pMiniLine, &rmi);
4963 dontRecalcStrSegMetrics = FALSE;
4964
4965 len = pMiniLine->w;
4966 if (len > (*pn_max_len)) (*pn_max_len) = len;
4967 } else {
4968 PushCurFont();
4969 if (!RecalcMiniLineMetrics(pMiniLine, &rmi)) {
4970 text_ptr->read_only = TRUE;
4971 }
4972 PopCurFont();
4973 }
4974 baseline_y += pMiniLine->des + v_space;
4975 if (pMiniLine->next != NULL) {
4976 baseline_y += pMiniLine->next->asc;
4977 }
4978 }
4979 *pn_max_h = baseline_y - text_ptr->baseline_y;
4980 }
4981 readingTextObject = FALSE;
4982
4983 return TRUE;
4984 }
4985
4986 static
OldStyleRotateGetFinalOBBoxLtXY(ObjPtr,rotate,text_just,pnFinalLtX,pnFinalLtY)4987 void OldStyleRotateGetFinalOBBoxLtXY(ObjPtr, rotate, text_just, pnFinalLtX,
4988 pnFinalLtY)
4989 struct ObjRec *ObjPtr;
4990 int rotate, text_just, *pnFinalLtX, *pnFinalLtY;
4991 /*
4992 * For fileVersion >= 33, rotate is always ROTATE0. So we need
4993 * to convert the old format to the new one. The way we will
4994 * do it is to:
4995 * 1) Calculate where the final obbox.ltx and obbox.lty will be.
4996 * 2) Rotate the object.
4997 * 3) Move the object to matched the final position calculated in (1).
4998 */
4999 {
5000 /*
5001 * This this point, coordinates in ObjPtr have been computed using ROTATE0.
5002 * Remember, positive rotate is clockwise.
5003 * In the old style, for JUST_L, pivot is left top corner, for JUST_C, pivot
5004 * is center top corner, and for JUST_R, pivot is right top corner.
5005 */
5006 int x=ObjPtr->x, y=ObjPtr->y, ltx=ObjPtr->obbox.ltx, lty=ObjPtr->obbox.lty;
5007 int w=ObjPtr->obbox.rbx-ltx, h=ObjPtr->obbox.rby-lty;
5008
5009 switch (rotate) {
5010 case ROTATE90:
5011 switch (text_just) {
5012 case JUST_L: ltx=x-h; lty=y; break;
5013 case JUST_C: ltx=x-h; lty=y-(w>>1); break;
5014 case JUST_R: ltx=x-h; lty=y-w; break;
5015 }
5016 break;
5017 case ROTATE180:
5018 switch (text_just) {
5019 case JUST_L: ltx=x-(w-(w>>1)); lty=y-h; break;
5020 case JUST_C: ltx=x-w; lty=y-h; break;
5021 case JUST_R: ltx=x; lty=y-h; break;
5022 }
5023 break;
5024 case ROTATE270:
5025 switch (text_just) {
5026 case JUST_L: ltx=x; lty=y-w; break;
5027 case JUST_C: ltx=x; lty=y-(w-(w>>1)); break;
5028 case JUST_R: ltx=x; lty=y; break;
5029 }
5030 break;
5031 }
5032 *pnFinalLtX = ltx;
5033 *pnFinalLtY = lty;
5034 }
5035
ReadTextObj(FP,Inbuf,ObjPtr)5036 void ReadTextObj(FP, Inbuf, ObjPtr)
5037 FILE *FP;
5038 char *Inbuf;
5039 struct ObjRec **ObjPtr;
5040 {
5041 int max_len=0, max_h=0, len;
5042 struct TextRec *text_ptr;
5043 char color_str[40], bg_color_str[40], *s, *c_ptr, font_str[MAXSTRING];
5044 char sb_font_str[MAXSTRING], inbuf[MAXSTRING+1];
5045 char cust_font_name[MAXSTRING+1]; /* this is not really used any more */
5046 int has_ps_bitmap=FALSE;
5047 int cur_sb_font=(-1), cur_db_font=(-1), baseline_y=0;
5048 int num_lines=0, x, y, font=0, style=0, size=0, sz_unit=0, id=0;
5049 int text_just=0, rotate=0, pen=0, rotation=0, adj_bbox_for_third_party=FALSE;
5050 int obbox_w=0, obbox_h=0, dpi=0, asc=0, des=0, fill=0, trans_pat=FALSE;
5051 int locked=FALSE, max_rextra=0, v_space=0, new_alloc=FALSE;
5052 int underline_on=FALSE, underline=2, min_lbearing=0;
5053 int underline_y_offset=0, overline_y_offset=0;
5054 int double_byte=FALSE, compressed=FALSE;
5055 int db_mod_bytes=FALSE, db_vertical=FALSE;
5056 int transformed=FALSE, invisible=FALSE;
5057 int direction=FontLeftToRight, real_x=0, real_y=0;
5058 int first_block_asc=0, first_block_des=0, text_w=0, text_h=0;
5059 struct XfrmMtrxRec *ctm=NULL;
5060 struct BBRec orig_obbox, orig_bbox;
5061
5062 dpi = FONT_DPI_75;
5063 fill = NONEPAT;
5064 v_space = 0;
5065 *cust_font_name = '\0';
5066 *font_str = *sb_font_str = '\0';
5067
5068 *ObjPtr = NULL;
5069
5070 s = FindChar((int)'(', Inbuf);
5071 s = ParseStr(s, (int)',', color_str, sizeof(color_str));
5072
5073 InitScan(s, ", \t\n");
5074
5075 rotate = 0;
5076 pen = 1;
5077 rotation = 0;
5078 if (fileVersion <= 2) {
5079 if (GETINT("text", x, "x") == INVALID ||
5080 GETINT("text", y, "y") == INVALID ||
5081 GETINT("text", font, "font") == INVALID ||
5082 GETINT("text", style, "style") == INVALID ||
5083 GETINT("text", size, "size") == INVALID ||
5084 GETINT("text", num_lines, "num_lines") == INVALID ||
5085 GETINT("text", text_just, "text_just") == INVALID) {
5086 return;
5087 }
5088 id = objId++;
5089 } else if (fileVersion <= 6) {
5090 if (GETINT("text", x, "x") == INVALID ||
5091 GETINT("text", y, "y") == INVALID ||
5092 GETINT("text", font, "font") == INVALID ||
5093 GETINT("text", style, "style") == INVALID ||
5094 GETINT("text", size, "size") == INVALID ||
5095 GETINT("text", num_lines, "num_lines") == INVALID ||
5096 GETINT("text", text_just, "text_just") == INVALID ||
5097 GETINT("text", rotate, "rotate") == INVALID ||
5098 GETINT("text", pen, "pen") == INVALID) {
5099 return;
5100 }
5101 id = objId++;
5102 } else if (fileVersion <= 7) {
5103 if (GETINT("text", x, "x") == INVALID ||
5104 GETINT("text", y, "y") == INVALID ||
5105 GETINT("text", font, "font") == INVALID ||
5106 GETINT("text", style, "style") == INVALID ||
5107 GETINT("text", size, "size") == INVALID ||
5108 GETINT("text", num_lines, "num_lines") == INVALID ||
5109 GETINT("text", text_just, "text_just") == INVALID ||
5110 GETINT("text", rotate, "rotate") == INVALID ||
5111 GETINT("text", pen, "pen") == INVALID ||
5112 GETINT("text", obbox_w, "bbox w") == INVALID ||
5113 GETINT("text", obbox_h, "bbox h") == INVALID) {
5114 return;
5115 }
5116 id = objId++;
5117 } else if (fileVersion <= 9) {
5118 if (GETINT("text", x, "x") == INVALID ||
5119 GETINT("text", y, "y") == INVALID ||
5120 GETINT("text", font, "font") == INVALID ||
5121 GETINT("text", style, "style") == INVALID ||
5122 GETINT("text", size, "size") == INVALID ||
5123 GETINT("text", num_lines, "num_lines") == INVALID ||
5124 GETINT("text", text_just, "text_just") == INVALID ||
5125 GETINT("text", rotate, "rotate") == INVALID ||
5126 GETINT("text", pen, "pen") == INVALID ||
5127 GETINT("text", obbox_w, "bbox w") == INVALID ||
5128 GETINT("text", obbox_h, "bbox h") == INVALID ||
5129 GETINT("text", id, "id") == INVALID ||
5130 GETINT("text", dpi, "dpi") == INVALID) {
5131 return;
5132 }
5133 if (id >= objId) objId = id+1;
5134 } else if (fileVersion <= 10) {
5135 if (GETINT("text", x, "x") == INVALID ||
5136 GETINT("text", y, "y") == INVALID ||
5137 GETINT("text", font, "font") == INVALID ||
5138 GETINT("text", style, "style") == INVALID ||
5139 GETINT("text", size, "size") == INVALID ||
5140 GETINT("text", num_lines, "num_lines") == INVALID ||
5141 GETINT("text", text_just, "text_just") == INVALID ||
5142 GETINT("text", rotate, "rotate") == INVALID ||
5143 GETINT("text", pen, "pen") == INVALID ||
5144 GETINT("text", obbox_w, "bbox w") == INVALID ||
5145 GETINT("text", obbox_h, "bbox h") == INVALID ||
5146 GETINT("text", id, "id") == INVALID ||
5147 GETINT("text", dpi, "dpi") == INVALID ||
5148 GETINT("text", asc, "ascent") == INVALID ||
5149 GETINT("text", des, "descent") == INVALID) {
5150 return;
5151 }
5152 if (id >= objId) objId = id+1;
5153 } else if (fileVersion <= 12) {
5154 if (GETINT("text", x, "x") == INVALID ||
5155 GETINT("text", y, "y") == INVALID ||
5156 GETINT("text", font, "font") == INVALID ||
5157 GETINT("text", style, "style") == INVALID ||
5158 GETINT("text", size, "size") == INVALID ||
5159 GETINT("text", num_lines, "num_lines") == INVALID ||
5160 GETINT("text", text_just, "text_just") == INVALID ||
5161 GETINT("text", rotate, "rotate") == INVALID ||
5162 GETINT("text", pen, "pen") == INVALID ||
5163 GETINT("text", obbox_w, "bbox w") == INVALID ||
5164 GETINT("text", obbox_h, "bbox h") == INVALID ||
5165 GETINT("text", id, "id") == INVALID ||
5166 GETINT("text", dpi, "dpi") == INVALID ||
5167 GETINT("text", asc, "ascent") == INVALID ||
5168 GETINT("text", des, "descent") == INVALID ||
5169 GETINT("text", fill, "fill") == INVALID) {
5170 return;
5171 }
5172 if (id >= objId) objId = id+1;
5173 } else if (fileVersion <= 13) {
5174 if (GETINT("text", x, "x") == INVALID ||
5175 GETINT("text", y, "y") == INVALID ||
5176 GETINT("text", font, "font") == INVALID ||
5177 GETINT("text", style, "style") == INVALID ||
5178 GETINT("text", size, "size") == INVALID ||
5179 GETINT("text", num_lines, "num_lines") == INVALID ||
5180 GETINT("text", text_just, "text_just") == INVALID ||
5181 GETINT("text", rotate, "rotate") == INVALID ||
5182 GETINT("text", pen, "pen") == INVALID ||
5183 GETINT("text", obbox_w, "bbox w") == INVALID ||
5184 GETINT("text", obbox_h, "bbox h") == INVALID ||
5185 GETINT("text", id, "id") == INVALID ||
5186 GETINT("text", dpi, "dpi") == INVALID ||
5187 GETINT("text", asc, "ascent") == INVALID ||
5188 GETINT("text", des, "descent") == INVALID ||
5189 GETINT("text", fill, "fill") == INVALID ||
5190 GETINT("text", v_space, "vertical spacing") == INVALID) {
5191 return;
5192 }
5193 if (id >= objId) objId = id+1;
5194 } else if (fileVersion <= 25) {
5195 if (GETINT("text", x, "x") == INVALID ||
5196 GETINT("text", y, "y") == INVALID ||
5197 GETINT("text", font, "font") == INVALID ||
5198 GETINT("text", style, "style") == INVALID ||
5199 GETINT("text", size, "size") == INVALID ||
5200 GETINT("text", num_lines, "num_lines") == INVALID ||
5201 GETINT("text", text_just, "text_just") == INVALID ||
5202 GETINT("text", rotate, "rotate") == INVALID ||
5203 GETINT("text", pen, "pen") == INVALID ||
5204 GETINT("text", obbox_w, "bbox w") == INVALID ||
5205 GETINT("text", obbox_h, "bbox h") == INVALID ||
5206 GETINT("text", id, "id") == INVALID ||
5207 GETINT("text", dpi, "dpi") == INVALID ||
5208 GETINT("text", asc, "ascent") == INVALID ||
5209 GETINT("text", des, "descent") == INVALID ||
5210 GETINT("text", fill, "fill") == INVALID ||
5211 GETINT("text", v_space, "vertical spacing") == INVALID ||
5212 GETINT("text", rotation, "rotation") == INVALID) {
5213 return;
5214 }
5215 if (id >= objId) objId = id+1;
5216 } else if (fileVersion <= 29) {
5217 if (GETINT("text", x, "x") == INVALID ||
5218 GETINT("text", y, "y") == INVALID ||
5219 GETINT("text", font, "font") == INVALID ||
5220 GETINT("text", style, "style") == INVALID ||
5221 GETINT("text", size, "size") == INVALID ||
5222 GETINT("text", num_lines, "num_lines") == INVALID ||
5223 GETINT("text", text_just, "text_just") == INVALID ||
5224 GETINT("text", rotate, "rotate") == INVALID ||
5225 GETINT("text", pen, "pen") == INVALID ||
5226 GETINT("text", obbox_w, "bbox w") == INVALID ||
5227 GETINT("text", obbox_h, "bbox h") == INVALID ||
5228 GETINT("text", id, "id") == INVALID ||
5229 GETINT("text", dpi, "dpi") == INVALID ||
5230 GETINT("text", asc, "ascent") == INVALID ||
5231 GETINT("text", des, "descent") == INVALID ||
5232 GETINT("text", fill, "fill") == INVALID ||
5233 GETINT("text", v_space, "vertical spacing") == INVALID ||
5234 GETINT("text", rotation, "rotation") == INVALID ||
5235 GETINT("text", locked, "locked") == INVALID) {
5236 return;
5237 }
5238 if (id >= objId) objId = id+1;
5239 } else if (fileVersion <= 32) {
5240 if (GETINT("text", x, "x") == INVALID ||
5241 GETINT("text", y, "y") == INVALID ||
5242 GETSTR("text", font_str, "font_str") == INVALID ||
5243 GETINT("text", style, "style") == INVALID ||
5244 GETINT("text", size, "size") == INVALID ||
5245 GETINT("text", num_lines, "num_lines") == INVALID ||
5246 GETINT("text", text_just, "text_just") == INVALID ||
5247 GETINT("text", rotate, "rotate") == INVALID ||
5248 GETINT("text", pen, "pen") == INVALID ||
5249 GETINT("text", obbox_w, "bbox w") == INVALID ||
5250 GETINT("text", obbox_h, "bbox h") == INVALID ||
5251 GETINT("text", id, "id") == INVALID ||
5252 GETINT("text", dpi, "dpi") == INVALID ||
5253 GETINT("text", asc, "ascent") == INVALID ||
5254 GETINT("text", des, "descent") == INVALID ||
5255 GETINT("text", fill, "fill") == INVALID ||
5256 GETINT("text", v_space, "vertical spacing") == INVALID ||
5257 GETINT("text", rotation, "rotation") == INVALID ||
5258 GETINT("text", locked, "locked") == INVALID) {
5259 return;
5260 }
5261 if (id >= objId) objId = id+1;
5262 } else if (fileVersion <= 33) {
5263 if (GETINT("text", x, "x") == INVALID ||
5264 GETINT("text", y, "y") == INVALID ||
5265 GETSTR("text", font_str, "font_str") == INVALID ||
5266 GETINT("text", style, "style") == INVALID ||
5267 GETINT("text", size, "size") == INVALID ||
5268 GETINT("text", num_lines, "num_lines") == INVALID ||
5269 GETINT("text", text_just, "text_just") == INVALID ||
5270 GETINT("text", rotate, "rotate") == INVALID ||
5271 GETINT("text", pen, "pen") == INVALID ||
5272 GETINT("text", obbox_w, "bbox w") == INVALID ||
5273 GETINT("text", obbox_h, "bbox h") == INVALID ||
5274 GETINT("text", id, "id") == INVALID ||
5275 GETINT("text", dpi, "dpi") == INVALID ||
5276 GETINT("text", asc, "ascent") == INVALID ||
5277 GETINT("text", des, "descent") == INVALID ||
5278 GETINT("text", fill, "fill") == INVALID ||
5279 GETINT("text", v_space, "vertical spacing") == INVALID ||
5280 GETINT("text", rotation, "rotation") == INVALID ||
5281 GETINT("text", locked, "locked") == INVALID ||
5282 GETINT("text", underline_on, "underline_on") == INVALID ||
5283 GETINT("text", underline, "underline") == INVALID ||
5284 GETINT("text", min_lbearing, "min_lbearing") == INVALID ||
5285 GETINT("text", max_rextra, "max_rextra") == INVALID ||
5286 GETINT("text", double_byte, "double_byte") == INVALID ||
5287 GETINT("text", direction, "direction") == INVALID ||
5288 GETSTR("text", cust_font_name, "cust_font_name") == INVALID ||
5289 GETINT("text", compressed, "compressed") == INVALID ||
5290 GETINT("text", transformed, "transformed") == INVALID ||
5291 GETINT("text", invisible, "invisible") == INVALID) {
5292 return;
5293 }
5294 if (id >= objId) objId = id+1;
5295 len = strlen(cust_font_name);
5296 if (len >= 2 && *cust_font_name=='"' && cust_font_name[len-1]=='"') {
5297 for (c_ptr=cust_font_name; c_ptr[2] != '\0'; c_ptr++) {
5298 *c_ptr = c_ptr[1];
5299 }
5300 *c_ptr = '\0';
5301 }
5302 } else if (fileVersion <= 34) {
5303 if (GETINT("text", x, "x") == INVALID ||
5304 GETINT("text", y, "y") == INVALID ||
5305 GETSTR("text", font_str, "font_str") == INVALID ||
5306 GETINT("text", style, "style") == INVALID ||
5307 GETINT("text", size, "size") == INVALID ||
5308 GETINT("text", num_lines, "num_lines") == INVALID ||
5309 GETINT("text", text_just, "text_just") == INVALID ||
5310 GETINT("text", rotate, "rotate") == INVALID ||
5311 GETINT("text", pen, "pen") == INVALID ||
5312 GETINT("text", obbox_w, "bbox w") == INVALID ||
5313 GETINT("text", obbox_h, "bbox h") == INVALID ||
5314 GETINT("text", id, "id") == INVALID ||
5315 GETINT("text", dpi, "dpi") == INVALID ||
5316 GETINT("text", asc, "ascent") == INVALID ||
5317 GETINT("text", des, "descent") == INVALID ||
5318 GETINT("text", fill, "fill") == INVALID ||
5319 GETINT("text", v_space, "vertical spacing") == INVALID ||
5320 GETINT("text", rotation, "rotation") == INVALID ||
5321 GETINT("text", locked, "locked") == INVALID ||
5322 GETINT("text", underline_on, "underline_on") == INVALID ||
5323 GETINT("text", underline, "underline") == INVALID ||
5324 GETINT("text", min_lbearing, "min_lbearing") == INVALID ||
5325 GETINT("text", max_rextra, "max_rextra") == INVALID ||
5326 GETINT("text", double_byte, "double_byte") == INVALID ||
5327 GETINT("text", direction, "direction") == INVALID ||
5328 GETSTR("text", cust_font_name, "cust_font_name") == INVALID ||
5329 GETINT("text", compressed, "compressed") == INVALID ||
5330 GETINT("text", transformed, "transformed") == INVALID ||
5331 GETINT("text", invisible, "invisible") == INVALID ||
5332 GETINT("text", has_ps_bitmap, "has_ps_bitmap") == INVALID) {
5333 return;
5334 }
5335 if (id >= objId) objId = id+1;
5336 len = strlen(cust_font_name);
5337 if (len >= 2 && *cust_font_name=='"' && cust_font_name[len-1]=='"') {
5338 for (c_ptr=cust_font_name; c_ptr[2] != '\0'; c_ptr++) {
5339 *c_ptr = c_ptr[1];
5340 }
5341 *c_ptr = '\0';
5342 }
5343 } else if (fileVersion <= 35) {
5344 if (GETINT("text", x, "x") == INVALID ||
5345 GETINT("text", y, "y") == INVALID ||
5346 GETSTR("text", font_str, "font_str") == INVALID ||
5347 GETINT("text", style, "style") == INVALID ||
5348 GETINT("text", size, "size") == INVALID ||
5349 GETINT("text", num_lines, "num_lines") == INVALID ||
5350 GETINT("text", text_just, "text_just") == INVALID ||
5351 GETINT("text", rotate, "rotate") == INVALID ||
5352 GETINT("text", pen, "pen") == INVALID ||
5353 GETINT("text", obbox_w, "bbox w") == INVALID ||
5354 GETINT("text", obbox_h, "bbox h") == INVALID ||
5355 GETINT("text", id, "id") == INVALID ||
5356 GETINT("text", dpi, "dpi") == INVALID ||
5357 GETINT("text", asc, "ascent") == INVALID ||
5358 GETINT("text", des, "descent") == INVALID ||
5359 GETINT("text", fill, "fill") == INVALID ||
5360 GETINT("text", v_space, "vertical spacing") == INVALID ||
5361 GETINT("text", rotation, "rotation") == INVALID ||
5362 GETINT("text", locked, "locked") == INVALID ||
5363 GETINT("text", underline_on, "underline_on") == INVALID ||
5364 GETINT("text", underline, "underline") == INVALID ||
5365 GETINT("text", min_lbearing, "min_lbearing") == INVALID ||
5366 GETINT("text", max_rextra, "max_rextra") == INVALID ||
5367 GETINT("text", double_byte, "double_byte") == INVALID ||
5368 GETINT("text", direction, "direction") == INVALID ||
5369 GETSTR("text", cust_font_name, "cust_font_name") == INVALID ||
5370 GETINT("text", compressed, "compressed") == INVALID ||
5371 GETINT("text", transformed, "transformed") == INVALID ||
5372 GETINT("text", invisible, "invisible") == INVALID ||
5373 GETINT("text", has_ps_bitmap, "has_ps_bitmap") == INVALID ||
5374 GETINT("text", db_mod_bytes, "double_byte_mod_bytes") == INVALID ||
5375 GETINT("text", db_vertical, "double_byte_vertical") == INVALID ||
5376 GETINT("text", trans_pat, "trans_pat") == INVALID) {
5377 return;
5378 }
5379 if (id >= objId) objId = id+1;
5380 len = strlen(cust_font_name);
5381 if (len >= 2 && *cust_font_name=='"' && cust_font_name[len-1]=='"') {
5382 for (c_ptr=cust_font_name; c_ptr[2] != '\0'; c_ptr++) {
5383 *c_ptr = c_ptr[1];
5384 }
5385 *c_ptr = '\0';
5386 }
5387 } else if (fileVersion <= 36) {
5388 if (GETINT("text", x, "x") == INVALID ||
5389 GETINT("text", y, "y") == INVALID ||
5390 GETSTR("text", font_str, "font_str") == INVALID ||
5391 GETINT("text", style, "style") == INVALID ||
5392 GETINT("text", sz_unit, "size unit") == INVALID ||
5393 GETINT("text", num_lines, "num_lines") == INVALID ||
5394 GETINT("text", text_just, "text_just") == INVALID ||
5395 GETINT("text", rotate, "rotate") == INVALID ||
5396 GETINT("text", pen, "pen") == INVALID ||
5397 GETINT("text", obbox_w, "bbox w") == INVALID ||
5398 GETINT("text", obbox_h, "bbox h") == INVALID ||
5399 GETINT("text", id, "id") == INVALID ||
5400 GETINT("text", dpi, "dpi") == INVALID ||
5401 GETINT("text", asc, "ascent") == INVALID ||
5402 GETINT("text", des, "descent") == INVALID ||
5403 GETINT("text", fill, "fill") == INVALID ||
5404 GETINT("text", v_space, "vertical spacing") == INVALID ||
5405 GETINT("text", rotation, "rotation") == INVALID ||
5406 GETINT("text", locked, "locked") == INVALID ||
5407 GETINT("text", underline_on, "underline_on") == INVALID ||
5408 GETINT("text", underline, "underline") == INVALID ||
5409 GETINT("text", min_lbearing, "min_lbearing") == INVALID ||
5410 GETINT("text", max_rextra, "max_rextra") == INVALID ||
5411 GETINT("text", double_byte, "double_byte") == INVALID ||
5412 GETINT("text", direction, "direction") == INVALID ||
5413 GETSTR("text", cust_font_name, "cust_font_name") == INVALID ||
5414 GETINT("text", compressed, "compressed") == INVALID ||
5415 GETINT("text", transformed, "transformed") == INVALID ||
5416 GETINT("text", invisible, "invisible") == INVALID ||
5417 GETINT("text", has_ps_bitmap, "has_ps_bitmap") == INVALID ||
5418 GETINT("text", db_mod_bytes, "double_byte_mod_bytes") == INVALID ||
5419 GETINT("text", db_vertical, "double_byte_vertical") == INVALID ||
5420 GETINT("text", trans_pat, "trans_pat") == INVALID) {
5421 return;
5422 }
5423 if (id >= objId) objId = id+1;
5424 len = strlen(cust_font_name);
5425 if (len >= 2 && *cust_font_name=='"' && cust_font_name[len-1]=='"') {
5426 for (c_ptr=cust_font_name; c_ptr[2] != '\0'; c_ptr++) {
5427 *c_ptr = c_ptr[1];
5428 }
5429 *c_ptr = '\0';
5430 }
5431 } else {
5432 if (GETINT("text", x, "x") == INVALID ||
5433 GETINT("text", y, "y") == INVALID ||
5434 GETINT("text", num_lines, "num_lines") == INVALID ||
5435 GETINT("text", text_just, "text_just") == INVALID ||
5436 GETINT("text", pen, "pen") == INVALID ||
5437 GETINT("text", obbox_w, "bbox w") == INVALID ||
5438 GETINT("text", obbox_h, "bbox h") == INVALID ||
5439 GETINT("text", id, "id") == INVALID ||
5440 GETINT("text", first_block_asc, "first block ascent") == INVALID ||
5441 GETINT("text", first_block_des, "first block descent") == INVALID ||
5442 GETINT("text", fill, "fill") == INVALID ||
5443 GETINT("text", v_space, "vertical spacing") == INVALID ||
5444 GETINT("text", rotation, "rotation") == INVALID ||
5445 GETINT("text", locked, "locked") == INVALID ||
5446 GETINT("text", underline, "underline") == INVALID ||
5447 GETINT("text", text_w, "text_w") == INVALID ||
5448 GETINT("text", text_h, "text_h") == INVALID ||
5449 GETINT("text", min_lbearing, "min_lbearing") == INVALID ||
5450 GETINT("text", max_rextra, "max_rextra") == INVALID ||
5451 GETSTR("text", cust_font_name, "cust_font_name") == INVALID ||
5452 GETINT("text", compressed, "compressed") == INVALID ||
5453 GETINT("text", transformed, "transformed") == INVALID ||
5454 GETINT("text", invisible, "invisible") == INVALID ||
5455 GETINT("text", trans_pat, "trans_pat") == INVALID ||
5456 GETINT("text", baseline_y, "baseline_y") == INVALID) {
5457 return;
5458 }
5459 /*
5460 * This is a hack! If the file version becomes >= 38, this code
5461 * must be removed!
5462 */
5463 if (GETSTR("text", bg_color_str, "bg_color_str") == INVALID) {
5464 /* should not get here because we should have read in: "[" */
5465 return;
5466 } else if (*bg_color_str == '[') {
5467 *bg_color_str = '\0';
5468 } else if (*bg_color_str == '\'') {
5469 UtilRemoveQuotes(bg_color_str);
5470 }
5471 if (id >= objId) objId = id+1;
5472 len = strlen(cust_font_name);
5473 if (len >= 2 && *cust_font_name=='"' && cust_font_name[len-1]=='"') {
5474 for (c_ptr=cust_font_name; c_ptr[2] != '\0'; c_ptr++) {
5475 *c_ptr = c_ptr[1];
5476 }
5477 *c_ptr = '\0';
5478 }
5479 }
5480 if (fileVersion >= 33 && transformed) {
5481 int do_adjust=FALSE, dx=0, t[2];
5482 double dreal_x, dreal_y, m[4];
5483
5484 (void)fgets(inbuf, MAXSTRING, FP);
5485 scanLineNum++;
5486 InitScan(inbuf, "\t\n, ");
5487
5488 ctm = (struct XfrmMtrxRec *)malloc(sizeof(struct XfrmMtrxRec));
5489 if (ctm == NULL) FailAllocMessage();
5490 if (GETDBL("text", dreal_x, "real_x") == INVALID ||
5491 GETDBL("text", dreal_y, "real_y") == INVALID ||
5492 GETINT("text", orig_obbox.ltx, "orig_obbox.ltx") == INVALID ||
5493 GETINT("text", orig_obbox.lty, "orig_obbox.lty") == INVALID ||
5494 GETINT("text", orig_obbox.rbx, "orig_obbox.rbx") == INVALID ||
5495 GETINT("text", orig_obbox.rby, "orig_obbox.rby") == INVALID ||
5496 GETDBL("text", m[CTM_SX], "CTM_SX") == INVALID ||
5497 GETDBL("text", m[CTM_SIN], "CTM_SIN") == INVALID ||
5498 GETDBL("text", m[CTM_MSIN], "CTM_MSIN") == INVALID ||
5499 GETDBL("text", m[CTM_SY], "CTM_SY") == INVALID ||
5500 GETINT("text", t[CTM_TX], "CTM_TX") == INVALID ||
5501 GETINT("text", t[CTM_TY], "CTM_TY") == INVALID ||
5502 GETINT("text", orig_bbox.ltx, "orig_bbox.ltx") == INVALID ||
5503 GETINT("text", orig_bbox.lty, "orig_bbox.lty") == INVALID ||
5504 GETINT("text", orig_bbox.rbx, "orig_bbox.rbx") == INVALID ||
5505 GETINT("text", orig_bbox.rby, "orig_bbox.rby") == INVALID) {
5506 return;
5507 }
5508 real_x = round(dreal_x);
5509 real_y = round(dreal_y);
5510 ctm->m[CTM_SX] = m[CTM_SX];
5511 ctm->m[CTM_SIN] = m[CTM_SIN];
5512 ctm->m[CTM_MSIN] = m[CTM_MSIN];
5513 ctm->m[CTM_SY] = m[CTM_SY];
5514 ctm->t[CTM_TX] = t[CTM_TX];
5515 ctm->t[CTM_TY] = t[CTM_TY];
5516 if (orig_obbox.ltx == 0 && orig_obbox.lty == 0 &&
5517 orig_obbox.rbx == 0 && orig_obbox.rby == 0) {
5518 adj_bbox_for_third_party = TRUE;
5519 }
5520 switch (text_just) {
5521 case JUST_L:
5522 if (real_x != orig_obbox.ltx) {
5523 dx = real_x - orig_obbox.ltx;
5524 do_adjust = TRUE;
5525 }
5526 break;
5527 case JUST_C:
5528 if (real_x != ((orig_obbox.ltx+orig_obbox.rbx)>>1)) {
5529 dx = real_x - ((orig_obbox.ltx+orig_obbox.rbx)>>1);
5530 do_adjust = TRUE;
5531 }
5532 break;
5533 case JUST_R:
5534 if (real_x != orig_obbox.rbx) {
5535 dx = real_x - orig_obbox.rbx;
5536 do_adjust = TRUE;
5537 }
5538 break;
5539 }
5540 if (adj_bbox_for_third_party || do_adjust) {
5541 orig_obbox.ltx += dx;
5542 orig_obbox.rbx += dx;
5543 orig_bbox.ltx += dx;
5544 orig_bbox.rbx += dx;
5545 }
5546 }
5547 if (fileVersion <= 36) {
5548 baseline_y = y+asc;
5549 if (ctm == NULL) {
5550 text_w = obbox_w;
5551 text_h = obbox_h;
5552 } else {
5553 text_w = orig_obbox.rbx-orig_obbox.ltx;
5554 text_h = orig_obbox.rby-orig_obbox.lty;
5555 }
5556 first_block_asc = asc;
5557 first_block_des = des;
5558 } else {
5559 asc = first_block_asc;
5560 des = first_block_des;
5561 }
5562 fill = UpgradePenFill(fill);
5563 pen = UpgradePenFill(pen);
5564
5565 *ObjPtr = (struct ObjRec *)malloc(sizeof(struct ObjRec));
5566 if (*ObjPtr == NULL) FailAllocMessage();
5567 memset(*ObjPtr, 0, sizeof(struct ObjRec));
5568
5569 text_ptr = (struct TextRec *)malloc(sizeof(struct TextRec));
5570 if (text_ptr == NULL) FailAllocMessage();
5571 memset(text_ptr, 0, sizeof(struct TextRec));
5572 text_ptr->lines = num_lines;
5573 text_ptr->cached_bitmap = None;
5574 text_ptr->cached_zoom = 0;
5575
5576 if (!PRTGIF) SaveCurFont();
5577
5578 if (fileVersion <= 36) {
5579 /* set curFont, curStyle, and curSzUnit */
5580 if (fileVersion <= 29) {
5581 GetCompatibleFontName(font, style, font_str);
5582 }
5583 ReadTextSetFontStyleSzUnit(font_str, sb_font_str, style, sz_unit,
5584 size, dpi, &double_byte, &cur_sb_font, &cur_db_font);
5585 } else {
5586 /* curFont, curStyle, and curSzUnit are undefined here */
5587 }
5588 if (fileVersion >= 37) {
5589 UncombineOverUnderYOffsets(underline, &underline_y_offset,
5590 &overline_y_offset);
5591 } else {
5592 underline_y_offset = underline;
5593 overline_y_offset = 0;
5594 }
5595 transPat = (*ObjPtr)->trans_pat = trans_pat;
5596
5597 textJust = text_ptr->minilines.just = text_just;
5598 textVSpace = text_ptr->minilines.v_space = v_space;
5599 canvasLineAsc = asc;
5600 canvasLineDes = des;
5601
5602 penPat = text_ptr->pen = pen;
5603 objFill = text_ptr->fill = fill;
5604 curUnderlineOn = (underline_on & 0x1);
5605 curOverlineOn = ((underline_on & 0x2) == 0x2);
5606 curUnderlineYOffset = text_ptr->underline_y_offset = underline_y_offset;
5607 curOverlineYOffset = text_ptr->overline_y_offset = overline_y_offset;
5608 curOverlineOn = FALSE;
5609
5610 /*
5611 * set canvasFontAsc, canvasFontDes, textCursorH, and canvasFontDoubleByte...
5612 */
5613 ReadTextSetCanvasFont(text_ptr, dpi, size, asc, des, double_byte,
5614 db_mod_bytes, db_vertical, direction);
5615 if (!PRTGIF && fileVersion <= 36) {
5616 baseline_y = y+canvasFontAsc;
5617 }
5618
5619 if (text_ptr->read_only) {
5620 switch (rotate) {
5621 case ROTATE0:
5622 case ROTATE180:
5623 text_ptr->orig_w = obbox_w;
5624 text_ptr->orig_h = obbox_h;
5625 break;
5626 case ROTATE90:
5627 case ROTATE270:
5628 text_ptr->orig_w = obbox_h;
5629 text_ptr->orig_h = obbox_w;
5630 break;
5631 }
5632 text_ptr->min_lbearing = min_lbearing;
5633 text_ptr->max_rextra = max_rextra;
5634 } else {
5635 text_ptr->orig_w = text_ptr->orig_h = 0;
5636 text_ptr->min_lbearing = text_ptr->max_rextra = 0;
5637 }
5638 text_ptr->baseline_y = baseline_y;
5639
5640 /*
5641 * Now read all the lines in.
5642 */
5643 firstMiniLine = lastMiniLine = NULL;
5644 if (!ReadTextLines(FP, ObjPtr, text_ptr, color_str, num_lines, has_ps_bitmap,
5645 cur_sb_font, cur_db_font, double_byte, db_mod_bytes, db_vertical,
5646 direction, x, baseline_y, text_w, &max_len, &max_h)) {
5647 if (!PRTGIF) RestoreCurFont();
5648 return;
5649 }
5650 text_ptr->minilines.first = firstMiniLine;
5651 text_ptr->minilines.last = lastMiniLine;
5652
5653 firstMiniLine = lastMiniLine = NULL;
5654 textCurIndex = 0;
5655
5656 if (!PRTGIF && !text_ptr->read_only) {
5657 RecalcTextMetrics(text_ptr, x, text_ptr->baseline_y);
5658
5659 max_len = text_ptr->w;
5660 max_h = text_ptr->h;
5661 min_lbearing = text_ptr->min_lbearing;
5662 max_rextra = text_ptr->max_rextra;
5663 }
5664 if (!PRTGIF) {
5665 if (text_ptr->minilines.baseline_offset != 0 ||
5666 text_ptr->minilines.first->v_gap != 0) {
5667 #ifdef _TGIF_DBG /* debug, do not translate */
5668 TgAssert(FALSE,
5669 "Non-zero first baseline_offset or v_gap in ReadTextObj()",
5670 "Fixed");
5671 #endif /* _TGIF_DBG */
5672 text_ptr->minilines.baseline_offset = 0;
5673 text_ptr->minilines.first->v_gap = 0;
5674 }
5675 y = text_ptr->baseline_y - text_ptr->minilines.first->asc +
5676 text_ptr->minilines.first->v_gap;
5677 }
5678 text_ptr->min_lbearing = min_lbearing;
5679 text_ptr->max_rextra = max_rextra;
5680 (*ObjPtr)->type = OBJ_TEXT;
5681 (*ObjPtr)->color = QuickFindColorIndex(*ObjPtr, color_str, &new_alloc, TRUE);
5682 UtilStrCpyN((*ObjPtr)->color_str, sizeof((*ObjPtr)->color_str), color_str);
5683 (*ObjPtr)->dirty = FALSE;
5684 (*ObjPtr)->id = id;
5685 (*ObjPtr)->rotation = rotation;
5686 (*ObjPtr)->locked = locked;
5687 (*ObjPtr)->detail.t = text_ptr;
5688 (*ObjPtr)->x = x;
5689 (*ObjPtr)->y = y; /* NOTE: this y is derived from text_ptr->baseline_y */
5690 (*ObjPtr)->ctm = ctm;
5691 (*ObjPtr)->invisible = invisible;
5692
5693 if (ctm != NULL) {
5694 memcpy(&(*ObjPtr)->orig_obbox, &orig_obbox, sizeof(struct BBRec));
5695 memcpy(&text_ptr->orig_bbox, &orig_bbox, sizeof(struct BBRec));
5696 (*ObjPtr)->x = real_x;
5697 (*ObjPtr)->y = real_y;
5698 if (adj_bbox_for_third_party) {
5699 SetTextOrigBBoxes(*ObjPtr, text_just, max_len, max_h,
5700 min_lbearing, max_rextra, rotate);
5701 }
5702 GetTransformedOBBoxOffsetVs(*ObjPtr, (*ObjPtr)->rotated_obbox);
5703 }
5704 /*
5705 * This this point, (*ObjPtr)->x, (*ObjPtr)->y, text_just, obbox_w, obbox_h,
5706 * max_len, min_lbearing, max_rextra, and rotate are all valid
5707 */
5708 if (PRTGIF && fileVersion > 6) {
5709 switch (rotate) {
5710 case ROTATE0:
5711 case ROTATE180:
5712 SetTextBBox(*ObjPtr, text_just, obbox_w, obbox_h,
5713 min_lbearing, max_rextra, rotate);
5714 break;
5715 case ROTATE90:
5716 case ROTATE270:
5717 SetTextBBox(*ObjPtr, text_just, obbox_h, obbox_w,
5718 min_lbearing, max_rextra, rotate);
5719 break;
5720 }
5721 } else if (!PRTGIF && text_ptr->read_only) {
5722 SetTextBBox(*ObjPtr, text_just, text_ptr->orig_w, text_ptr->orig_h,
5723 min_lbearing, max_rextra, rotate);
5724 } else {
5725 if (fileVersion < 33 && rotate != ROTATE0) {
5726 /* pretend there's no rotate so we can get the coordiantes for obbox */
5727 SetTextBBox(*ObjPtr, text_just, max_len, max_h,
5728 min_lbearing, max_rextra, ROTATE0);
5729 } else {
5730 SetTextBBox(*ObjPtr, text_just, max_len, max_h,
5731 min_lbearing, max_rextra, rotate);
5732 }
5733 }
5734 if (fileVersion < 33 && rotate != ROTATE0) {
5735 int ltx=0, lty=0, saved_rotation_increment=rotationIncrement;
5736
5737 /*
5738 * For fileVersion >= 33, rotate is always ROTATE0. So we need
5739 * to convert the old format to the new one. The way we will
5740 * do it is to:
5741 * 1) Calculate where the final obbox.ltx and obbox.lty will be.
5742 * 2) Rotate the object.
5743 * 3) Move the object to matched the final position calculated in (1).
5744 *
5745 * Well, turns out this is not needed!
5746 */
5747 OldStyleRotateGetFinalOBBoxLtXY(*ObjPtr, rotate, text_just, <x, <y);
5748
5749 SetRotatePivotByObject(*ObjPtr);
5750 switch (rotate) {
5751 case ROTATE90: rotationIncrement = (90<<6); break;
5752 case ROTATE180: rotationIncrement = (180<<6); break;
5753 case ROTATE270: rotationIncrement = (270<<6); break;
5754 }
5755 RotateObjClockWise(*ObjPtr);
5756 rotationIncrement = saved_rotation_increment;
5757 }
5758 if (!PRTGIF && ctm != NULL &&
5759 strcmp(gGenerateByInfo.name, "pstoedit") == 0) {
5760 int asc=text_ptr->minilines.first->first_block->asc, dx=0, dy=0;
5761
5762 text_ptr->baseline_y = (*ObjPtr)->y + asc;
5763 TransformPointThroughCTM(0, asc, ctm, &dx, &dy);
5764 MoveObj(*ObjPtr, -dx, -dy);
5765 }
5766 if (!PRTGIF) RestoreCurFont();
5767 }
5768
UpdCurTextBBox()5769 void UpdCurTextBBox()
5770 {
5771 struct TextRec *text_ptr=curTextObj->detail.t;
5772 MiniLinesInfo *minilines=NULL;
5773
5774 if (!textCursorShown) return;
5775
5776 RecalcTextMetrics(text_ptr, textOrigX, text_ptr->baseline_y);
5777 minilines = (&text_ptr->minilines);
5778
5779 SetTextCurXY();
5780 if (textHighlight) SetTextEndXY();
5781
5782 UpdateEditTextArea(minilines->w, minilines->h, minilines->min_lbearing,
5783 minilines->max_rextra);
5784 }
5785
AdjustCurText(XOff,YOff)5786 void AdjustCurText(XOff, YOff)
5787 int XOff, YOff;
5788 {
5789 textOrigX += XOff;
5790 textOrigY += YOff;
5791 textOrigBaselineY += YOff;
5792 textCurX += XOff;
5793 textCurY += YOff;
5794 textCurBaselineY += YOff;
5795 textEndX += XOff;
5796 textEndY += YOff;
5797 textEndBaselineY += YOff;
5798 }
5799
PrepareZoomCurText(AbsXc,AbsYc)5800 void PrepareZoomCurText(AbsXc, AbsYc)
5801 int *AbsXc, *AbsYc;
5802 {
5803 switch (textJust) {
5804 case JUST_L: *AbsXc = ABS_X(textOrigX+(textW>>1)); break;
5805 case JUST_C: *AbsXc = ABS_X(textOrigX); break;
5806 case JUST_R: *AbsXc = ABS_X(textOrigX-(textW>>1)); break;
5807 }
5808 *AbsYc = ABS_Y(textOrigY+(textH>>1));
5809 }
5810
PreZoomCurText()5811 void PreZoomCurText()
5812 {
5813 InvalidateTextCache(curTextObj->detail.t);
5814 }
5815
PostZoomCurText(AbsXc,AbsYc)5816 void PostZoomCurText(AbsXc, AbsYc)
5817 int AbsXc, AbsYc;
5818 {
5819 int x=0, y=0, orig_text_w=0, orig_text_h=0;
5820
5821 switch (textJust) {
5822 case JUST_L: x = OFFSET_X(AbsXc)-(textW>>1); break;
5823 case JUST_C: x = OFFSET_X(AbsXc); break;
5824 case JUST_R: x = OFFSET_X(AbsXc)+(textW>>1); break;
5825 }
5826 y = OFFSET_Y(AbsYc)-(textH>>1);
5827 AdjustCurText(x-textOrigX, y-textOrigY);
5828 textAbsX -= (tmpAdjAbsX+curTextMovedAbsX);
5829 textAbsY -= (tmpAdjAbsY+curTextMovedAbsY);
5830 textAbsBaselineY -= (tmpAdjAbsY+curTextMovedAbsY);
5831
5832 if (editTextSize != 0) {
5833 if (RestoreEditTextSize(curTextObj, TRUE)) {
5834 UpdTextBBox(curTextObj);
5835 }
5836 }
5837 orig_text_w = curTextObj->obbox.rbx - curTextObj->obbox.ltx;
5838 orig_text_h = curTextObj->obbox.rby - curTextObj->obbox.lty;
5839
5840 if (editTextSize != 0) {
5841 if (RestoreEditTextSize(curTextObj, FALSE)) {
5842 UpdTextBBox(curTextObj);
5843 }
5844 }
5845 switch (textJust) {
5846 case JUST_L: tmpAdjAbsX = (orig_text_w-ABS_SIZE(textW))/2; break;
5847 case JUST_C: tmpAdjAbsX = 0; break;
5848 case JUST_R: tmpAdjAbsX = (ABS_SIZE(textW)-orig_text_w)/2; break;
5849 }
5850 tmpAdjAbsY = (orig_text_h-ABS_SIZE(textH))/2;
5851
5852 textAbsX += (tmpAdjAbsX+curTextMovedAbsX);
5853 textAbsY += (tmpAdjAbsY+curTextMovedAbsY);
5854 textAbsBaselineY += (tmpAdjAbsY+curTextMovedAbsY);
5855
5856 SetTextCurXY();
5857 SetTextEndXY();
5858 RedrawCurText();
5859 UpdateTextInfoChoices(FALSE);
5860 }
5861
HighLightText(obj_ptr,pStartStrBlock,start_index,pEndStrBlock,end_index)5862 void HighLightText(obj_ptr, pStartStrBlock, start_index, pEndStrBlock,
5863 end_index)
5864 struct ObjRec *obj_ptr;
5865 StrBlockInfo *pStartStrBlock, *pEndStrBlock;
5866 int start_index, end_index;
5867 {
5868 int abs_x=0, abs_y=0, x_off=0, y_off=0;
5869 int update_highlighted_text_bboxes=FALSE;
5870
5871 if (curChoice == DRAWTEXT && textCursorShown) {
5872 if (textHighlight) {
5873 update_highlighted_text_bboxes = TRUE;
5874 } else {
5875 EraseTextCursor();
5876 }
5877 escPressed = FALSE;
5878 CreateTextObj(TRUE, TRUE);
5879 curTextModified = FALSE;
5880 }
5881 outerSel = outerSelForFind;
5882 innerSel = innerSelForFind;
5883 outerSelForFind = innerSelForFind = NULL;
5884 abs_x = obj_ptr->x; x_off = OFFSET_X(abs_x);
5885 abs_y = obj_ptr->detail.t->baseline_y; y_off = OFFSET_Y(abs_y);
5886
5887 curTextModified = FALSE;
5888 if (!PrepareEditExistingText(obj_ptr, abs_x, abs_y, &x_off, &y_off)) {
5889 return;
5890 }
5891 if (update_highlighted_text_bboxes && curStrBlock != NULL) {
5892 UpdateHighLightedTextBBoxes(TRUE);
5893 }
5894 HandleClickOnText(FALSE, TRUE, x_off, y_off, FALSE, curTextObj, FALSE, TRUE,
5895 TRUE, (Time)0);
5896
5897 if (pStartStrBlock == NULL) {
5898 curStrBlock = curTextObj->detail.t->minilines.first->first_block;
5899 textCurIndex = 0;
5900 ResetOnCursorKey(FALSE);
5901 } else {
5902 curStrBlock = pStartStrBlock;
5903 textCurIndex = start_index;
5904 endStrBlock = pEndStrBlock;
5905 textEndIndex = end_index;
5906 }
5907 SetTextHighlight();
5908
5909 SetTextCurXY();
5910 if (endStrBlock != NULL) SetTextEndXY();
5911 textJustClicked = FALSE;
5912
5913 UpdatePinnedMenu(MENU_EDIT);
5914 RedrawCurText();
5915 ScrollTo(textCurX, textCurBaselineY);
5916 UpdateTextInfoChoices(FALSE);
5917 }
5918
FindTextInCurTextObj(str_to_match,str_len,case_sensitive,ppFoundStartStrBlock,pn_start_index,ppFoundEndStrBlock,pn_end_index)5919 int FindTextInCurTextObj(str_to_match, str_len, case_sensitive,
5920 ppFoundStartStrBlock, pn_start_index, ppFoundEndStrBlock, pn_end_index)
5921 char *str_to_match;
5922 int str_len, case_sensitive, *pn_start_index, *pn_end_index;
5923 StrBlockInfo **ppFoundStartStrBlock, **ppFoundEndStrBlock;
5924 {
5925 int found_starting_point=FALSE;
5926 MiniLinesInfo *minilines=(&curTextObj->detail.t->minilines);
5927
5928 SaveCursorPositionInCurText();
5929
5930 if (textHighlight) {
5931 ReorderCursorStrBlocks();
5932 SetTextHighlight();
5933 UpdatePinnedMenu(MENU_EDIT);
5934 }
5935 *ppFoundStartStrBlock = *ppFoundEndStrBlock = NULL;
5936 *pn_start_index = *pn_end_index = INVALID;
5937 /*
5938 * This is what's going on in FindStringInMiniLines()...
5939 * First, find curStrBlock. Set *pn_found_starting_point to TRUE
5940 * once curStrBlock is found.
5941 * After curStrBlock is found, if *ppStartStrBlock is NULL, this means
5942 * that we are still trying to find a prefix match.
5943 * If *ppStartStrBlock is non-NULL, that means the prefix is found, so
5944 * we must match starting at the beginning of every string.
5945 */
5946 if (FindStringInMiniLines(minilines, &found_starting_point,
5947 str_to_match, str_len, case_sensitive, ppFoundStartStrBlock,
5948 pn_start_index, ppFoundEndStrBlock, pn_end_index)) {
5949 RestoreCursorPositionInCurText();
5950 return TRUE;
5951 }
5952 RestoreCursorPositionInCurText();
5953
5954 return FALSE;
5955 }
5956
5957 /* --------------------- Insert Special Routines --------------------- */
5958
SetScriptFractionValue(spec)5959 int SetScriptFractionValue(spec)
5960 char *spec;
5961 {
5962 float fv=(float)0.0;
5963 char buf[80];
5964
5965 fv = (float)atof(spec);
5966 UtilStrCpyN(buf, sizeof(buf), spec);
5967 if (fabs(fv - ((double)1.01)) < INT_TOL) {
5968 fv = (float)1.0;
5969 strcpy(buf, "1.0");
5970 } else if (fabs(fv - ((double)0.2)) < INT_TOL) {
5971 fv = (float)0.2;
5972 strcpy(buf, "0.2");
5973 } else if (fv < 0.2 || fv > 1.01) {
5974 sprintf(gszMsgBox, TgLoadString(STID_INVALID_GIVEN_VALUE_SPECIFIED), spec);
5975 if (PRTGIF) {
5976 fprintf(stderr, "%s\n", gszMsgBox);
5977 } else {
5978 Msg(gszMsgBox);
5979 }
5980 return FALSE;
5981 }
5982 if (strcmp(spec, scriptFractionStr) != 0) {
5983 scriptFraction = fv;
5984 strcpy(scriptFractionStr, buf);
5985 }
5986 return TRUE;
5987 }
5988
SetScriptFraction()5989 void SetScriptFraction()
5990 {
5991 char spec[MAXSTRING+1];
5992
5993 *spec = '\0';
5994 sprintf(gszMsgBox, TgLoadString(STID_ENTER_SCRIPT_FRACTION_CUR_IS),
5995 scriptFractionStr);
5996 if (Dialog(gszMsgBox, NULL, spec) == INVALID) return;
5997 UtilTrimBlanks(spec);
5998 if (*spec == '\0') return;
5999
6000 if (SetScriptFractionValue(spec)) {
6001 sprintf(gszMsgBox, TgLoadString(STID_SCRIPT_FRACTION_SET_TO_STR),
6002 scriptFractionStr);
6003 Msg(gszMsgBox);
6004 }
6005 }
6006
6007 static
CanInsertThinSpace()6008 int CanInsertThinSpace()
6009 {
6010 return (textCursorShown && curStrBlock != NULL &&
6011 curStrBlock->type != SB_SUPSUB_CENTER && !textHighlight);
6012 }
6013
InsertThinSpace()6014 void InsertThinSpace()
6015 {
6016 int w=0;
6017 char spec[MAXSTRING];
6018
6019 if (!CanInsertThinSpace()) return;
6020
6021 *spec = '\0';
6022 if (Dialog(TgLoadString(STID_ENTER_INT_WIDTH_FOR_THIN_SPC), NULL, spec) ==
6023 INVALID) {
6024 return;
6025 }
6026 UtilTrimBlanks(spec);
6027 if (*spec == '\0') return;
6028 w = atoi(spec);
6029 if (w == 0) {
6030 sprintf(gszMsgBox, TgLoadString(STID_INVALID_GIVEN_VALUE_SPECIFIED),
6031 spec);
6032 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
6033 return;
6034 }
6035 escPressed = FALSE;
6036
6037 ResetDirtyBBoxInfo();
6038 curTextModified = TRUE;
6039 if (textHighlight) {
6040 /* Well, should never get here! */
6041 #ifdef _TGIF_DBG /* debug, do not translate */
6042 TgAssert(FALSE, "textHighlight in InsertThinSpace()", NULL);
6043 #endif /* _TGIF_DBG */
6044 InsertHighlightedThinSpace(w);
6045 } else {
6046 DoInsertThinSpace(w);
6047 }
6048 EndChangeCurText(FALSE);
6049 MarkRulers(textCurX, textCurY);
6050 SetFileModified(TRUE);
6051 ScrollTo(textCurX, textCurBaselineY);
6052 }
6053
6054 static
CanInsertOrRemoveVerticalOffset()6055 int CanInsertOrRemoveVerticalOffset()
6056 {
6057 if (textCursorShown && !textHighlight && curStrBlock != NULL &&
6058 curStrBlock->type == SB_SIMPLE) {
6059 MiniLinesInfo *minilines=(&curTextObj->detail.t->minilines);
6060
6061 if (curStrBlock->owner_mini_line->owner_minilines == minilines &&
6062 curStrBlock->owner_mini_line == minilines->first) {
6063 return FALSE;
6064 }
6065 return TRUE;
6066 }
6067 return FALSE;
6068 }
6069
6070 static
DoInsertVerticalOffset(baseline_offset)6071 void DoInsertVerticalOffset(baseline_offset)
6072 int baseline_offset;
6073 {
6074 MiniLinesInfo *pOwnerMinilines=NULL;
6075
6076 ResetOnCursorKey(FALSE);
6077
6078 switch(curStrBlock->type) {
6079 case SB_SIMPLE:
6080 pOwnerMinilines = curStrBlock->owner_mini_line->owner_minilines;
6081 if (curStrBlock->owner_mini_line == pOwnerMinilines->first) {
6082 pOwnerMinilines->baseline_offset += baseline_offset;
6083 } else {
6084 curStrBlock->owner_mini_line->v_gap += baseline_offset;
6085 }
6086 break;
6087 case SB_CHAR_SPACE: /* not possible */ return;
6088 case SB_SUPSUB_LEFT: /* not possible */ return;
6089 case SB_SUPSUB_RIGHT: /* not possible */ return;
6090 case SB_SUPSUB_CENTER: /* not possible */ return;
6091 }
6092 EndChangeCurText(FALSE);
6093 MarkRulers(textCurX, textCurY);
6094 SetFileModified(TRUE);
6095 ScrollTo(textCurX, textCurBaselineY);
6096 }
6097
InsertVerticalOffset()6098 void InsertVerticalOffset()
6099 {
6100 int baseline_offset=0;
6101 char spec[MAXSTRING];
6102
6103 if (!CanInsertOrRemoveVerticalOffset()) return;
6104
6105 *spec = '\0';
6106 if (Dialog(TgLoadString(STID_ENTER_INT_VAL_FOR_VERT_OFFSET), NULL, spec) ==
6107 INVALID) {
6108 return;
6109 }
6110 UtilTrimBlanks(spec);
6111 if (*spec == '\0') return;
6112 baseline_offset = atoi(spec);
6113 if (baseline_offset == 0) {
6114 return;
6115 }
6116 ResetOnCursorKey(TRUE);
6117 SetTextHighlight();
6118 UpdatePinnedMenu(MENU_EDIT);
6119
6120 ResetDirtyBBoxInfo();
6121 curTextModified = TRUE;
6122
6123 DoInsertVerticalOffset(baseline_offset);
6124 }
6125
6126 static
DoRemoveVerticalOffset()6127 void DoRemoveVerticalOffset()
6128 {
6129 MiniLinesInfo *pOwnerMinilines=NULL;
6130
6131 ResetOnCursorKey(FALSE);
6132
6133 switch(curStrBlock->type) {
6134 case SB_SIMPLE:
6135 pOwnerMinilines = curStrBlock->owner_mini_line->owner_minilines;
6136 if (curStrBlock->owner_mini_line == pOwnerMinilines->first) {
6137 pOwnerMinilines->baseline_offset = 0;
6138 } else {
6139 curStrBlock->owner_mini_line->v_gap = 0;
6140 }
6141 break;
6142 case SB_CHAR_SPACE: /* not possible */ return;
6143 case SB_SUPSUB_LEFT: /* not possible */ return;
6144 case SB_SUPSUB_RIGHT: /* not possible */ return;
6145 case SB_SUPSUB_CENTER: /* not possible */ return;
6146 }
6147 EndChangeCurText(FALSE);
6148 MarkRulers(textCurX, textCurY);
6149 SetFileModified(TRUE);
6150 ScrollTo(textCurX, textCurBaselineY);
6151 }
6152
RemoveVerticalOffset()6153 void RemoveVerticalOffset()
6154 {
6155 if (!CanInsertOrRemoveVerticalOffset()) return;
6156
6157 ResetOnCursorKey(TRUE);
6158 SetTextHighlight();
6159 UpdatePinnedMenu(MENU_EDIT);
6160
6161 ResetDirtyBBoxInfo();
6162 curTextModified = TRUE;
6163
6164 DoRemoveVerticalOffset();
6165 }
6166
6167 #define INSERT_SUPERSCRIPT (TRUE)
6168 #define INSERT_SUBSCRIPT (FALSE)
6169
6170 static
CanInsertLeftRightScripts()6171 int CanInsertLeftRightScripts()
6172 {
6173 return (textCursorShown && !textHighlight && curStrBlock != NULL &&
6174 curStrBlock->type != SB_SUPSUB_CENTER);
6175 }
6176
6177 static
CreateMinilinesForInsertScripts(type)6178 MiniLinesInfo *CreateMinilinesForInsertScripts(type)
6179 int type;
6180 /* assuming curFont, curStyle, curSzUnit, textVSpace are all correct */
6181 {
6182 MiniLinesInfo *new_minilines=NewMiniLines();
6183
6184 SetCanvasFont();
6185
6186 CreateMiniLineFromString("", &new_minilines->first, &new_minilines->last);
6187
6188 switch (type) {
6189 case SB_SUPSUB_LEFT: new_minilines->just = JUST_R; break;
6190 case SB_SUPSUB_CENTER: new_minilines->just = JUST_C; break;
6191 case SB_SUPSUB_RIGHT: new_minilines->just = JUST_L; break;
6192 }
6193 new_minilines->v_space = textVSpace;
6194 new_minilines->first->first_block->seg->sz_unit = curSzUnit;
6195
6196 return new_minilines;
6197 }
6198
6199 static
DetermineWhatToDoForLeftRightScripts(type,pnJustMove,pnSplitAtIndex,pnInsertBefore)6200 void DetermineWhatToDoForLeftRightScripts(type, pnJustMove,
6201 pnSplitAtIndex, pnInsertBefore)
6202 int type, *pnJustMove, *pnSplitAtIndex, *pnInsertBefore;
6203 {
6204 if (textCurIndex == 0 && curStrBlock->seg->dyn_str.sz == 1) {
6205 if (type == SB_SUPSUB_LEFT && curStrBlock->prev != NULL &&
6206 curStrBlock->prev->type == type) {
6207 *pnJustMove = TRUE;
6208 return;
6209 } else if (type == SB_SUPSUB_RIGHT && curStrBlock->next != NULL &&
6210 curStrBlock->next->type == type) {
6211 *pnJustMove = TRUE;
6212 return;
6213 }
6214 if ((type == SB_SUPSUB_LEFT && curStrBlock->prev == NULL) ||
6215 (type == SB_SUPSUB_RIGHT && curStrBlock->next == NULL)) {
6216 *pnSplitAtIndex = TRUE;
6217 return;
6218 }
6219 }
6220 if (textCurIndex == 0) {
6221 if (curStrBlock->prev == NULL) {
6222 *pnSplitAtIndex = TRUE;
6223 } else if (curStrBlock->prev->type == SB_SIMPLE) {
6224 *pnInsertBefore = TRUE;
6225 } else {
6226 if (curStrBlock->prev->type == type && type == SB_SUPSUB_LEFT) {
6227 *pnJustMove = TRUE;
6228 } else {
6229 *pnSplitAtIndex = TRUE;
6230 }
6231 }
6232 } else if (textCurIndex == curStrBlock->seg->dyn_str.sz-1) {
6233 if (curStrBlock->next == NULL) {
6234 *pnSplitAtIndex = TRUE;
6235 } else if (curStrBlock->next->type == SB_SIMPLE) {
6236 *pnInsertBefore = FALSE;
6237 } else {
6238 if (curStrBlock->next->type == type && type == SB_SUPSUB_RIGHT) {
6239 *pnJustMove = TRUE;
6240 } else {
6241 *pnSplitAtIndex = TRUE;
6242 }
6243 }
6244 } else {
6245 *pnSplitAtIndex = TRUE;
6246 }
6247 }
6248
6249 static
GetNewSize(pStrSeg,pn_new_size)6250 void GetNewSize(pStrSeg, pn_new_size)
6251 StrSegInfo *pStrSeg;
6252 int *pn_new_size;
6253 {
6254 int new_sz_unit=0;
6255
6256 if (editTextSize != 0) {
6257 new_sz_unit = round(((double)pStrSeg->real_sz_unit) *
6258 ((double)scriptFraction));
6259 } else {
6260 new_sz_unit = round(((double)pStrSeg->sz_unit) *
6261 ((double)scriptFraction));
6262 }
6263 if (pn_new_size != NULL) {
6264 *pn_new_size = SzUnitToFontSize(new_sz_unit);
6265 }
6266 }
6267
6268 static
DoInsertLeftRightScripts(type,superscript)6269 int DoInsertLeftRightScripts(type, superscript)
6270 int type, superscript;
6271 {
6272 int just_move=FALSE, split_at_index=FALSE, insert_before=FALSE;
6273 int new_size=0, cur_v_space=textVSpace, font_h=0;
6274 MiniLineInfo *owner_mini_line=curStrBlock->owner_mini_line;
6275 StrBlockInfo *pSupSubStrBlock=NULL;
6276
6277 PushCurFont();
6278 if (editTextSize != 0) {
6279 if (RestoreEditTextSize(curTextObj, TRUE)) {
6280 UpdTextBBox(curTextObj);
6281 }
6282 }
6283 CopyCurInfoFromStrSeg(curStrBlock->seg);
6284
6285 GetNewSize(curStrBlock->seg, &new_size);
6286
6287 if (!TrySetCanvasFont(curFont, curStyle, new_size, TRUE, NULL)) {
6288 if (editTextSize != 0) {
6289 if (RestoreEditTextSize(curTextObj, FALSE)) {
6290 UpdTextBBox(curTextObj);
6291 }
6292 }
6293 PopCurFont();
6294 return FALSE;
6295 }
6296 DetermineWhatToDoForLeftRightScripts(type, &just_move, &split_at_index,
6297 &insert_before);
6298
6299 if (just_move) {
6300 if (type == SB_SUPSUB_LEFT) {
6301 pSupSubStrBlock = curStrBlock->prev;
6302 } else {
6303 pSupSubStrBlock = curStrBlock->next;
6304 }
6305 } else {
6306 pSupSubStrBlock = NewStrBlock();
6307 pSupSubStrBlock->type = type;
6308 pSupSubStrBlock->owner_mini_line = owner_mini_line;
6309
6310 if (split_at_index) {
6311 StrBlockInfo *pLeftStrBlock=NULL;
6312 char *psz=UtilStrDup(curStrBlock->seg->dyn_str.s), saved_ch='\0';
6313
6314 if (psz == NULL) FailAllocMessage();
6315
6316 DupStrBlock(curStrBlock, owner_mini_line, &pLeftStrBlock,
6317 &pLeftStrBlock);
6318 saved_ch = psz[textCurIndex];
6319 psz[textCurIndex] = '\0';
6320 DynStrSet(&pLeftStrBlock->seg->dyn_str, psz);
6321 psz[textCurIndex] = saved_ch;
6322 DynStrSet(&curStrBlock->seg->dyn_str, &psz[textCurIndex]);
6323 UtilFree(psz);
6324
6325 pLeftStrBlock->prev = curStrBlock->prev;
6326 if (curStrBlock->prev == NULL) {
6327 owner_mini_line->first_block = pLeftStrBlock;
6328 } else {
6329 curStrBlock->prev->next = pLeftStrBlock;
6330 }
6331 pLeftStrBlock->next = pSupSubStrBlock;
6332 pSupSubStrBlock->prev = pLeftStrBlock;
6333
6334 pSupSubStrBlock->next = curStrBlock;
6335 curStrBlock->prev = pSupSubStrBlock;
6336 } else if (insert_before) {
6337 pSupSubStrBlock->prev = curStrBlock->prev;
6338 curStrBlock->prev->next = pSupSubStrBlock;
6339
6340 pSupSubStrBlock->next = curStrBlock;
6341 curStrBlock->prev = pSupSubStrBlock;
6342 } else {
6343 /* insert after */
6344 pSupSubStrBlock->next = curStrBlock->next;
6345 curStrBlock->next->prev = pSupSubStrBlock;
6346
6347 pSupSubStrBlock->prev = curStrBlock;
6348 curStrBlock->next = pSupSubStrBlock;
6349 }
6350 pSupSubStrBlock->sup = CreateMinilinesForInsertScripts(type);
6351 font_h = pSupSubStrBlock->sup->first->first_block->seg->asc +
6352 pSupSubStrBlock->sup->first->first_block->seg->des;
6353 pSupSubStrBlock->sup->baseline_offset = -curStrBlock->seg->asc +
6354 curStrBlock->seg->des + (font_h>>1) -
6355 pSupSubStrBlock->sup->first->first_block->seg->des;
6356
6357 pSupSubStrBlock->sub = CreateMinilinesForInsertScripts(type);
6358 font_h = pSupSubStrBlock->sub->first->first_block->seg->asc +
6359 pSupSubStrBlock->sub->first->first_block->seg->des;
6360 pSupSubStrBlock->sub->baseline_offset = (font_h>>1) -
6361 pSupSubStrBlock->sub->first->first_block->seg->des;
6362 }
6363 if (superscript) {
6364 curStrBlock = pSupSubStrBlock->sup->first->first_block;
6365 } else {
6366 curStrBlock = pSupSubStrBlock->sub->first->first_block;
6367 }
6368 textCurIndex = 0;
6369 textVSpace = cur_v_space;
6370
6371 if (editTextSize != 0) {
6372 if (RestoreEditTextSize(curTextObj, FALSE)) {
6373 UpdTextBBox(curTextObj);
6374 }
6375 }
6376 PopCurFont();
6377
6378 EndChangeCurText(FALSE);
6379
6380 MarkRulers(textCurX, textCurY);
6381 SetFileModified(TRUE);
6382 ScrollTo(textCurX, textCurBaselineY);
6383
6384 return TRUE;
6385 }
6386
6387 static
InsertLeftRightScripts(type,superscript)6388 void InsertLeftRightScripts(type, superscript)
6389 int type, superscript;
6390 {
6391 escPressed = FALSE;
6392
6393 ResetDirtyBBoxInfo();
6394 if (!DoInsertLeftRightScripts(type, superscript)) {
6395 MsgBox(TgLoadString(STID_FAIL_INSERT_SCRIPT_FONT_SZ), TOOL_NAME, INFO_MB);
6396 } else {
6397 curTextModified = TRUE;
6398 }
6399 }
6400
InsertRightSuperscript()6401 void InsertRightSuperscript()
6402 {
6403 if (!CanInsertLeftRightScripts()) return;
6404
6405 InsertLeftRightScripts(SB_SUPSUB_RIGHT, INSERT_SUPERSCRIPT);
6406 }
6407
InsertRightSubscript()6408 void InsertRightSubscript()
6409 {
6410 if (!CanInsertLeftRightScripts()) return;
6411
6412 InsertLeftRightScripts(SB_SUPSUB_RIGHT, INSERT_SUBSCRIPT);
6413 }
6414
InsertLeftSuperscript()6415 void InsertLeftSuperscript()
6416 {
6417 if (!CanInsertLeftRightScripts()) return;
6418
6419 InsertLeftRightScripts(SB_SUPSUB_LEFT, INSERT_SUPERSCRIPT);
6420 }
6421
InsertLeftSubscript()6422 void InsertLeftSubscript()
6423 {
6424 if (!CanInsertLeftRightScripts()) return;
6425
6426 InsertLeftRightScripts(SB_SUPSUB_LEFT, INSERT_SUBSCRIPT);
6427 }
6428
6429 static
CanInsertCenterScripts()6430 int CanInsertCenterScripts()
6431 {
6432 if (textCursorShown) {
6433 if (textHighlight) {
6434 if (curStrBlock == endStrBlock && textCurIndex != textEndIndex) {
6435 return TRUE;
6436 }
6437 } else if (curStrBlock->type == SB_SUPSUB_CENTER) {
6438 return TRUE;
6439 }
6440 }
6441 return FALSE;
6442 }
6443
6444 static
DoInsertCenterScripts(superscript)6445 int DoInsertCenterScripts(superscript)
6446 int superscript;
6447 {
6448 int new_size=0;
6449 MiniLineInfo *owner_mini_line=curStrBlock->owner_mini_line;
6450
6451 PushCurFont();
6452 CopyCurInfoFromStrSeg(curStrBlock->seg);
6453
6454 GetNewSize(curStrBlock->seg, &new_size);
6455
6456 if (!TrySetCanvasFont(curFont, curStyle, new_size, TRUE, NULL)) {
6457 PopCurFont();
6458 return FALSE;
6459 }
6460 if (curStrBlock->type == SB_SUPSUB_CENTER) {
6461 if (superscript) {
6462 curStrBlock = curStrBlock->sup->first->first_block;
6463 } else {
6464 curStrBlock = curStrBlock->sub->first->first_block;
6465 }
6466 } else {
6467 int min_index=min(textCurIndex, textEndIndex);
6468 int max_index=max(textCurIndex, textEndIndex);
6469 StrBlockInfo *pLeftStrBlock=NULL, *pRightStrBlock=curStrBlock;
6470 StrBlockInfo *pCenterStrBlock=NULL;
6471 char *psz=NULL, saved_ch='\0';
6472
6473 pCenterStrBlock = NewStrBlock();
6474 pCenterStrBlock->type = SB_SUPSUB_CENTER;
6475 pCenterStrBlock->owner_mini_line = owner_mini_line;
6476 DupStrSeg(pCenterStrBlock, curStrBlock->seg);
6477
6478 psz = UtilStrDup(curStrBlock->seg->dyn_str.s);
6479 if (psz == NULL) FailAllocMessage();
6480
6481 DupStrBlock(pRightStrBlock, owner_mini_line, &pLeftStrBlock,
6482 &pLeftStrBlock);
6483 saved_ch = psz[min_index];
6484 psz[min_index] = '\0';
6485 DynStrSet(&pLeftStrBlock->seg->dyn_str, psz);
6486 psz[min_index] = saved_ch;
6487 DynStrSet(&pRightStrBlock->seg->dyn_str, &psz[max_index]);
6488 psz[max_index] = '\0';
6489 DynStrSet(&pCenterStrBlock->seg->dyn_str, &psz[min_index]);
6490 UtilFree(psz);
6491
6492 pLeftStrBlock->prev = pRightStrBlock->prev;
6493 if (pRightStrBlock->prev == NULL) {
6494 owner_mini_line->first_block = pLeftStrBlock;
6495 } else {
6496 pRightStrBlock->prev->next = pLeftStrBlock;
6497 }
6498 pLeftStrBlock->next = pCenterStrBlock;
6499 pCenterStrBlock->prev = pLeftStrBlock;
6500
6501 pCenterStrBlock->next = pRightStrBlock;
6502 pRightStrBlock->prev = pCenterStrBlock;
6503
6504 pCenterStrBlock->sup = CreateMinilinesForInsertScripts(SB_SUPSUB_CENTER);
6505 /*
6506 * pCenterStrBlock->sup->baseline_offset =
6507 * (-pCenterStrBlock->sup->first->first_block->seg->des);
6508 */
6509 pCenterStrBlock->sup->baseline_offset = 0;
6510
6511 pCenterStrBlock->sub = CreateMinilinesForInsertScripts(SB_SUPSUB_CENTER);
6512 /*
6513 * pCenterStrBlock->sub->baseline_offset =
6514 * pCenterStrBlock->sub->first->first_block->seg->asc;
6515 */
6516 pCenterStrBlock->sub->baseline_offset =
6517 (pCenterStrBlock->sub->first->first_block->seg->asc -
6518 pCenterStrBlock->seg->des);
6519 if (superscript) {
6520 curStrBlock = pCenterStrBlock->sup->first->first_block;
6521 } else {
6522 curStrBlock = pCenterStrBlock->sub->first->first_block;
6523 }
6524 /* consolidate */
6525 if (*pLeftStrBlock->seg->dyn_str.s == '\0') {
6526 if (pLeftStrBlock->prev != NULL &&
6527 pLeftStrBlock->prev->type == SB_SIMPLE) {
6528 UnlinkStrBlock(pLeftStrBlock);
6529 FreeStrBlock(pLeftStrBlock);
6530 pLeftStrBlock = NULL;
6531 }
6532 }
6533 if (*pRightStrBlock->seg->dyn_str.s == '\0') {
6534 if (pRightStrBlock->next != NULL &&
6535 pRightStrBlock->next->type == SB_SIMPLE) {
6536 UnlinkStrBlock(pRightStrBlock);
6537 FreeStrBlock(pRightStrBlock);
6538 pRightStrBlock = NULL;
6539 }
6540 }
6541 }
6542 textCurIndex = 0;
6543 ResetOnCursorKey(FALSE);
6544 SetTextHighlight();
6545
6546 PopCurFont();
6547
6548 EndChangeCurText(FALSE);
6549
6550 UpdatePinnedMenu(MENU_EDIT);
6551 MarkRulers(textCurX, textCurY);
6552 SetFileModified(TRUE);
6553 ScrollTo(textCurX, textCurBaselineY);
6554
6555 return TRUE;
6556 }
6557
6558 static
InsertCenterScripts(superscript)6559 void InsertCenterScripts(superscript)
6560 int superscript;
6561 {
6562 escPressed = FALSE;
6563
6564 ResetDirtyBBoxInfo();
6565 if (!DoInsertCenterScripts(superscript)) {
6566 MsgBox(TgLoadString(STID_FAIL_INSERT_SCRIPT_FONT_SZ), TOOL_NAME, INFO_MB);
6567 } else {
6568 curTextModified = TRUE;
6569 }
6570 }
6571
InsertCenterSuperscript()6572 void InsertCenterSuperscript()
6573 {
6574 if (!CanInsertCenterScripts()) return;
6575
6576 InsertCenterScripts(INSERT_SUPERSCRIPT);
6577 }
6578
InsertCenterSubscript()6579 void InsertCenterSubscript()
6580 {
6581 if (!CanInsertCenterScripts()) return;
6582
6583 InsertCenterScripts(INSERT_SUBSCRIPT);
6584 }
6585
RefreshEditTextMenu(menu)6586 int RefreshEditTextMenu(menu)
6587 TgMenu *menu;
6588 {
6589 int ok=TRUE;
6590
6591 ok &= TgEnableMenuItemById(menu, CMDID_INSERTTHINSPACE,
6592 CanInsertThinSpace());
6593 ok &= TgEnableMenuItemById(menu, CMDID_INSERTVERTICALOFFSET,
6594 CanInsertOrRemoveVerticalOffset());
6595
6596 ok &= TgEnableMenuItemById(menu, CMDID_INSERTRIGHTSUPERSCRIPT,
6597 CanInsertLeftRightScripts());
6598 ok &= TgEnableMenuItemById(menu, CMDID_INSERTRIGHTSUBSCRIPT,
6599 CanInsertLeftRightScripts());
6600 ok &= TgEnableMenuItemById(menu, CMDID_INSERTLEFTSUPERSCRIPT,
6601 CanInsertLeftRightScripts());
6602 ok &= TgEnableMenuItemById(menu, CMDID_INSERTLEFTSUBSCRIPT,
6603 CanInsertLeftRightScripts());
6604 ok &= TgEnableMenuItemById(menu, CMDID_INSERTCENTERSUPERSCRIPT,
6605 CanInsertCenterScripts());
6606 ok &= TgEnableMenuItemById(menu, CMDID_INSERTCENTERSUBSCRIPT,
6607 CanInsertCenterScripts());
6608
6609 ok &= TgEnableMenuItemById(menu, CMDID_RESETINMETHOD,
6610 gnInputMethod != TGIM_NONE);
6611
6612 return ok;
6613 }
6614
CreateEditTextMenu(parent_menu,x,y,menu_info,status_str_xlated)6615 TgMenu *CreateEditTextMenu(parent_menu, x, y, menu_info, status_str_xlated)
6616 TgMenu *parent_menu;
6617 int x, y;
6618 TgMenuInfo *menu_info;
6619 int status_str_xlated; /* ignored, always 0 */
6620 {
6621 TgMenu *menu=TgCreateMenuFromMenuInfo(parent_menu, x, y, menu_info, FALSE);
6622
6623 if (menu != NULL) {
6624 if (!RefreshEditTextMenu(menu)) {
6625 return TgDestroyMenu(menu, TRUE);
6626 }
6627 }
6628 return menu;
6629 }
6630
6631 static
DetermineWhatToDoForChangeProperty(lWhich,nValue,pStrBlock,nIndex,pnMoveLeft,pnMoveRight,pnSplitAtIndex,pnInsertBefore)6632 void DetermineWhatToDoForChangeProperty(lWhich, nValue, pStrBlock, nIndex,
6633 pnMoveLeft, pnMoveRight, pnSplitAtIndex, pnInsertBefore)
6634 long lWhich;
6635 int nValue;
6636 StrBlockInfo *pStrBlock;
6637 int nIndex, *pnMoveLeft, *pnMoveRight, *pnSplitAtIndex, *pnInsertBefore;
6638 {
6639 if (nIndex == 0) {
6640 if (pStrBlock->prev == NULL) {
6641 *pnInsertBefore = TRUE;
6642 } else if (pStrBlock->prev->type == SB_SIMPLE) {
6643 if (SameProperty(lWhich, nValue, pStrBlock->prev->seg, FALSE)) {
6644 *pnMoveLeft = TRUE;
6645 } else {
6646 *pnInsertBefore = TRUE;
6647 }
6648 } else {
6649 *pnInsertBefore = TRUE;
6650 }
6651 } else if (nIndex == pStrBlock->seg->dyn_str.sz-1) {
6652 if (pStrBlock->next == NULL) {
6653 *pnInsertBefore = FALSE;
6654 } else if (pStrBlock->next->type == SB_SIMPLE) {
6655 if (SameProperty(lWhich, nValue, pStrBlock->next->seg, FALSE)) {
6656 *pnMoveRight = TRUE;
6657 } else {
6658 *pnInsertBefore = FALSE;
6659 }
6660 } else {
6661 *pnInsertBefore = FALSE;
6662 }
6663 } else {
6664 *pnSplitAtIndex = TRUE;
6665 }
6666 }
6667
6668 static
ChangeEditTextPropertyAtCursor(lWhich,nValue)6669 int ChangeEditTextPropertyAtCursor(lWhich, nValue)
6670 long lWhich;
6671 int nValue;
6672 {
6673 StrBlockInfo *pNewStrBlock=NULL;
6674 MiniLineInfo *owner_mini_line=curStrBlock->owner_mini_line;
6675 int move_left=FALSE, move_right=FALSE;
6676 int split_at_index=FALSE, insert_before=FALSE;
6677
6678 DetermineWhatToDoForChangeProperty(lWhich, nValue, curStrBlock, textCurIndex,
6679 &move_left, &move_right, &split_at_index, &insert_before);
6680 if (move_left) {
6681 curStrBlock = curStrBlock->prev;
6682 textCurIndex = curStrBlock->seg->dyn_str.sz-1;
6683 } else if (move_right) {
6684 curStrBlock = curStrBlock->next;
6685 textCurIndex = 0;
6686 } else {
6687 DupStrBlock(curStrBlock, owner_mini_line, &pNewStrBlock,
6688 &pNewStrBlock);
6689 DynStrSet(&pNewStrBlock->seg->dyn_str, "");
6690 if (lWhich == PROP_MASK_TEXT_FONT &&
6691 curStrBlock->seg->double_byte != IsFontDoubleByte(nValue)) {
6692 pNewStrBlock->seg->double_byte = IsFontDoubleByte(nValue);
6693 if (pNewStrBlock->seg->double_byte) {
6694 pNewStrBlock->seg->double_byte_vertical =
6695 IsDoubleByteFontVertical(nValue, pNewStrBlock->seg->style);
6696 } else {
6697 pNewStrBlock->seg->double_byte_vertical = FALSE;
6698 }
6699 }
6700 if (!SetStrSegProperty(lWhich, nValue, pNewStrBlock->seg)) {
6701 /*
6702 * don't call UnlinkStrBlock() because DupStrBlock() does not
6703 * insert pNewStrBlock into owner_mini_line
6704 */
6705 FreeStrBlock(pNewStrBlock);
6706 return FALSE;
6707 }
6708 if (split_at_index) {
6709 StrBlockInfo *pLeftStrBlock=NULL;
6710 char *psz=UtilStrDup(curStrBlock->seg->dyn_str.s), saved_ch='\0';
6711
6712 if (psz == NULL) FailAllocMessage();
6713
6714 DupStrBlock(curStrBlock, owner_mini_line, &pLeftStrBlock,
6715 &pLeftStrBlock);
6716 saved_ch = psz[textCurIndex];
6717 psz[textCurIndex] = '\0';
6718 DynStrSet(&pLeftStrBlock->seg->dyn_str, psz);
6719 psz[textCurIndex] = saved_ch;
6720 DynStrSet(&curStrBlock->seg->dyn_str, &psz[textCurIndex]);
6721 UtilFree(psz);
6722
6723 pLeftStrBlock->prev = curStrBlock->prev;
6724 if (curStrBlock->prev == NULL) {
6725 owner_mini_line->first_block = pLeftStrBlock;
6726 } else {
6727 curStrBlock->prev->next = pLeftStrBlock;
6728 }
6729 pLeftStrBlock->next = pNewStrBlock;
6730 pNewStrBlock->prev = pLeftStrBlock;
6731
6732 pNewStrBlock->next = curStrBlock;
6733 curStrBlock->prev = pNewStrBlock;
6734 } else if (insert_before) {
6735 pNewStrBlock->prev = curStrBlock->prev;
6736 if (curStrBlock->prev == NULL) {
6737 owner_mini_line->first_block = pNewStrBlock;
6738 } else {
6739 curStrBlock->prev->next = pNewStrBlock;
6740 }
6741 pNewStrBlock->next = curStrBlock;
6742 curStrBlock->prev = pNewStrBlock;
6743 } else {
6744 /* insert after */
6745 pNewStrBlock->next = curStrBlock->next;
6746 if (curStrBlock->next == NULL) {
6747 owner_mini_line->last_block = pNewStrBlock;
6748 } else {
6749 curStrBlock->next->prev = pNewStrBlock;
6750 }
6751 pNewStrBlock->prev = curStrBlock;
6752 curStrBlock->next = pNewStrBlock;
6753 }
6754 curStrBlock = pNewStrBlock;
6755 textCurIndex = 0;
6756 }
6757 return TRUE;
6758 }
6759
ChangeEditTextProperty(lWhich,nValue)6760 int ChangeEditTextProperty(lWhich, nValue)
6761 long lWhich;
6762 int nValue;
6763 /* returns TRUE if anything is changed */
6764 {
6765 int changed=FALSE;
6766
6767 ResetDirtyBBoxInfo();
6768
6769 PushCurFont();
6770 if (editTextSize != 0) {
6771 if (RestoreEditTextSize(curTextObj, TRUE)) {
6772 UpdTextBBox(curTextObj);
6773 }
6774 }
6775 if (curStrBlock->type == SB_SUPSUB_CENTER) {
6776 if (SameProperty(lWhich, nValue, curStrBlock->seg, TRUE)) {
6777 /* nothing need to change */
6778 changed = FALSE;
6779 } else {
6780 int saved_double_byte=INVALID;
6781 int saved_double_byte_vertical=INVALID;
6782 int saved_double_byte_mod_bytes=INVALID;
6783
6784 if (lWhich == PROP_MASK_TEXT_FONT &&
6785 curStrBlock->seg->double_byte != IsFontDoubleByte(nValue)) {
6786 saved_double_byte = curStrBlock->seg->double_byte;
6787 saved_double_byte_vertical = curStrBlock->seg->double_byte_vertical;
6788 saved_double_byte_mod_bytes =
6789 curStrBlock->seg->double_byte_mod_bytes;
6790 curStrBlock->seg->double_byte = IsFontDoubleByte(nValue);
6791 }
6792 changed = SetStrSegProperty(lWhich, nValue, curStrBlock->seg);
6793 if (!changed && saved_double_byte != INVALID) {
6794 curStrBlock->seg->double_byte = saved_double_byte;
6795 curStrBlock->seg->double_byte_vertical = saved_double_byte_vertical;
6796 curStrBlock->seg->double_byte_mod_bytes =
6797 saved_double_byte_mod_bytes;
6798 }
6799 }
6800 } else {
6801 if (textHighlight) {
6802 changed = ChangeHighlightedTextProperty(lWhich, nValue);
6803 } else {
6804 if (SameProperty(lWhich, nValue, curStrBlock->seg, FALSE)) {
6805 /* nothing need to change */
6806 changed = FALSE;
6807 } else if (textCurIndex == 0 && curStrBlock->seg->dyn_str.sz == 1) {
6808 int saved_double_byte=INVALID;
6809 int saved_double_byte_vertical=INVALID;
6810 int saved_double_byte_mod_bytes=INVALID;
6811
6812 if (lWhich == PROP_MASK_TEXT_FONT &&
6813 curStrBlock->seg->double_byte != IsFontDoubleByte(nValue)) {
6814 saved_double_byte = curStrBlock->seg->double_byte;
6815 saved_double_byte_vertical =
6816 curStrBlock->seg->double_byte_vertical;
6817 saved_double_byte_mod_bytes =
6818 curStrBlock->seg->double_byte_mod_bytes;
6819 curStrBlock->seg->double_byte = IsFontDoubleByte(nValue);
6820 }
6821 changed = SetStrSegProperty(lWhich, nValue, curStrBlock->seg);
6822 if (!changed && saved_double_byte != INVALID) {
6823 curStrBlock->seg->double_byte = saved_double_byte;
6824 curStrBlock->seg->double_byte_vertical =
6825 saved_double_byte_vertical;
6826 curStrBlock->seg->double_byte_mod_bytes =
6827 saved_double_byte_mod_bytes;
6828 }
6829 } else {
6830 changed = ChangeEditTextPropertyAtCursor(lWhich, nValue);
6831 }
6832 }
6833 }
6834 if (editTextSize != 0) {
6835 if (RestoreEditTextSize(curTextObj, FALSE)) {
6836 UpdTextBBox(curTextObj);
6837 }
6838 }
6839 PopCurFont();
6840
6841 if (changed) {
6842 EndChangeCurText(FALSE);
6843 if (editTextSize != 0 && curStrBlock != NULL &&
6844 (curStrBlock->type == SB_SIMPLE ||
6845 curStrBlock->type == SB_SUPSUB_CENTER)) {
6846 CurFontMsg(TRUE, TRUE, curStrBlock->seg);
6847 } else {
6848 CurFontMsg(TRUE, TRUE, NULL);
6849 }
6850 SetFileModified(TRUE);
6851 }
6852 return changed;
6853 }
6854
6855 static
SplitCurStrBlock()6856 void SplitCurStrBlock()
6857 {
6858 StrBlockInfo *pLeftStrBlock=NULL;
6859 MiniLineInfo *owner_mini_line=curStrBlock->owner_mini_line;
6860 char *buf=NULL, saved_ch='\0';
6861
6862 DupStrBlock(curStrBlock, owner_mini_line, &pLeftStrBlock, &pLeftStrBlock);
6863 buf = curStrBlock->seg->dyn_str.s;
6864 saved_ch = buf[textCurIndex];
6865 buf[textCurIndex] = '\0';
6866 DynStrSet(&pLeftStrBlock->seg->dyn_str, buf);
6867 buf[textCurIndex] = saved_ch;
6868 DynStrSet(&curStrBlock->seg->dyn_str, &buf[textCurIndex]);
6869
6870 pLeftStrBlock->prev = curStrBlock->prev;
6871 if (curStrBlock->prev == NULL) {
6872 owner_mini_line->first_block = pLeftStrBlock;
6873 } else {
6874 curStrBlock->prev->next = pLeftStrBlock;
6875 }
6876 pLeftStrBlock->next = curStrBlock;
6877 curStrBlock->prev = pLeftStrBlock;
6878
6879 textCurIndex = 0;
6880 }
6881
PasteMiniLinesAtCursor(partial_text_obj_ptr)6882 void PasteMiniLinesAtCursor(partial_text_obj_ptr)
6883 struct ObjRec *partial_text_obj_ptr;
6884 {
6885 struct TextRec *src_text_ptr=partial_text_obj_ptr->detail.t;
6886 MiniLinesInfo *src_minilines=(&src_text_ptr->minilines);
6887 MiniLineInfo *src_mini_line=NULL, *next_mini_line=NULL;
6888 MiniLineInfo *pFirstMiniLine=NULL, *pLastMiniLine=NULL;
6889 StrBlockInfo *src_str_block=NULL, *next_str_block=NULL;
6890 StrBlockInfo *pFirstStrBlock=NULL, *pLastStrBlock=NULL;
6891
6892 ResetDirtyBBoxInfo();
6893 if (textHighlight) {
6894 DeleteHighlightedText();
6895 EndChangeCurText(FALSE);
6896 }
6897 if (editTextSize != 0) {
6898 if (RestoreEditTextSize(curTextObj, TRUE)) {
6899 UpdTextBBox(curTextObj);
6900 }
6901 }
6902 SplitCurStrBlock();
6903
6904 pFirstStrBlock = curStrBlock->owner_mini_line->first_block;
6905 pLastStrBlock = curStrBlock->owner_mini_line->last_block;
6906 for (src_str_block=src_minilines->first->first_block; src_str_block != NULL;
6907 src_str_block=next_str_block) {
6908 next_str_block = src_str_block->next;
6909 src_str_block->owner_mini_line = curStrBlock->owner_mini_line;
6910 InsertStrBlock(curStrBlock->prev, curStrBlock, src_str_block,
6911 &pFirstStrBlock, &pLastStrBlock);
6912 }
6913 curStrBlock->owner_mini_line->first_block = pFirstStrBlock;
6914 curStrBlock->owner_mini_line->last_block = pLastStrBlock;
6915
6916 if (src_minilines->first->next != NULL) {
6917 InsertCRLFIntoCurText();
6918 EndChangeCurText(TRUE);
6919
6920 pFirstMiniLine = curStrBlock->owner_mini_line->owner_minilines->first;
6921 pLastMiniLine = curStrBlock->owner_mini_line->owner_minilines->last;
6922 for (src_mini_line=src_minilines->first->next;
6923 src_mini_line->next != NULL; src_mini_line=next_mini_line) {
6924 next_mini_line = src_mini_line->next;
6925 src_mini_line->owner_minilines =
6926 curStrBlock->owner_mini_line->owner_minilines;
6927 InsertMiniLine(curStrBlock->owner_mini_line->prev,
6928 curStrBlock->owner_mini_line, src_mini_line, &pFirstMiniLine,
6929 &pLastMiniLine);
6930 }
6931 curStrBlock->owner_mini_line->owner_minilines->first = pFirstMiniLine;
6932 curStrBlock->owner_mini_line->owner_minilines->last = pLastMiniLine;
6933
6934 pFirstStrBlock = curStrBlock->owner_mini_line->first_block;
6935 pLastStrBlock = curStrBlock->owner_mini_line->last_block;
6936 for (src_str_block=src_mini_line->first_block;
6937 src_str_block != NULL; src_str_block=next_str_block) {
6938 next_str_block = src_str_block->next;
6939 src_str_block->owner_mini_line = curStrBlock->owner_mini_line;
6940 InsertStrBlock(curStrBlock->prev, curStrBlock, src_str_block,
6941 &pFirstStrBlock, &pLastStrBlock);
6942 }
6943 curStrBlock->owner_mini_line->first_block = pFirstStrBlock;
6944 curStrBlock->owner_mini_line->last_block = pLastStrBlock;
6945 }
6946 if (editTextSize != 0) {
6947 if (RestoreEditTextSize(curTextObj, FALSE)) {
6948 UpdTextBBox(curTextObj);
6949 }
6950 }
6951 EndChangeCurText(TRUE);
6952 MarkRulers(textCurX, textCurY);
6953 SetFileModified(TRUE);
6954
6955 ScrollTo(textCurX, textCurBaselineY);
6956
6957 if (src_minilines->first != NULL) {
6958 if (src_minilines->first != src_minilines->last) {
6959 free(src_minilines->last);
6960 }
6961 free(src_minilines->first);
6962 src_minilines->first = src_minilines->last = NULL;
6963 }
6964 }
6965
6966 /* --------------------- Insert Special Routines --------------------- */
6967
6968 static
DoMoveEditText(dx,dy)6969 void DoMoveEditText(dx, dy)
6970 int dx, dy;
6971 {
6972 struct TextRec *text_ptr=curTextObj->detail.t;
6973 int abs_dx=ABS_SIZE(dx), abs_dy=ABS_SIZE(dy), w=0, h=0;
6974
6975 curTextMovedAbsX += abs_dx;
6976 curTextMovedAbsY += abs_dy;
6977
6978 textAbsX += abs_dx;
6979 textAbsY += abs_dy;
6980 textAbsBaselineY += abs_dy;
6981
6982 textOrigX = OFFSET_X(textAbsX);
6983 textOrigY = OFFSET_Y(textAbsY);
6984 textOrigBaselineY = textOrigY + text_ptr->baseline_y - curTextObj->y;
6985
6986 SetTextCurXY();
6987 if (textHighlight) SetTextEndXY();
6988
6989 w = text_ptr->minilines.w;
6990 h = (textOrigBaselineY - textOrigY) +
6991 (text_ptr->minilines.h - text_ptr->minilines.first->asc);
6992
6993 SetEditTextArea(w, h, text_ptr->minilines.min_lbearing,
6994 text_ptr->minilines.max_rextra);
6995 }
6996
6997 static
ContinueMoveEditText(OrigX,OrigY)6998 void ContinueMoveEditText(OrigX, OrigY)
6999 int OrigX, OrigY;
7000 {
7001 int done=FALSE, abort=FALSE, dx=0, dy=0;
7002 int saved_x=OrigX, saved_y=OrigY;
7003 XEvent input, ev;
7004 struct BBRec bbox;
7005
7006 GetCurTextBBoxes(NULL, &bbox);
7007 InflateBBox(&bbox, -2, -2, &bbox);
7008
7009 if (!debugNoPointerGrab) {
7010 XGrabPointer(mainDisplay, drawWindow, FALSE,
7011 PointerMotionMask | ButtonReleaseMask,
7012 GrabModeAsync, GrabModeAsync, None, moveCursor, CurrentTime);
7013 }
7014 while (!done) {
7015 XNextEvent(mainDisplay, &input);
7016
7017 if (input.type == Expose || input.type == VisibilityNotify) {
7018 ExposeEventHandler(&input, TRUE);
7019 } else if (input.type == ButtonRelease) {
7020 XUngrabPointer(mainDisplay, CurrentTime);
7021 SelBox(drawWindow, revDefaultGC, bbox.ltx+dx, bbox.lty+dy,
7022 bbox.rbx+dx, bbox.rby+dy);
7023 done = TRUE;
7024 } else if (input.type == MotionNotify) {
7025 int cur_x=input.xmotion.x, cur_y=input.xmotion.y;
7026
7027 if (cur_x != saved_x || cur_y != saved_y) {
7028 SelBox(drawWindow, revDefaultGC, bbox.ltx+dx, bbox.lty+dy,
7029 bbox.rbx+dx, bbox.rby+dy);
7030 saved_x = cur_x;
7031 saved_y = cur_y;
7032 dx = saved_x-OrigX;
7033 dy = saved_y-OrigY;
7034 SelBox(drawWindow, revDefaultGC, bbox.ltx+dx, bbox.lty+dy,
7035 bbox.rbx+dx, bbox.rby+dy);
7036 }
7037 while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
7038 } else if (input.type == KeyPress) {
7039 if (KeyPressEventIsEscape(&input.xkey)) {
7040 XUngrabPointer(mainDisplay, CurrentTime);
7041 SelBox(drawWindow, revDefaultGC, bbox.ltx+dx, bbox.lty+dy,
7042 bbox.rbx+dx, bbox.rby+dy);
7043 abort = TRUE;
7044 done = TRUE;
7045 }
7046 }
7047 }
7048 SelBox(drawWindow, revDefaultGC, bbox.ltx, bbox.lty, bbox.rbx, bbox.rby);
7049 if (debugNoPointerGrab) XSync(mainDisplay, False);
7050
7051 if (!abort && (OrigX != saved_x || OrigY != saved_y)) {
7052 int abs_dx=ABS_SIZE(dx), abs_dy=ABS_SIZE(dy);
7053 struct BBRec new_bbox;
7054
7055 bbox.ltx = ABS_X(bbox.ltx); bbox.lty = ABS_Y(bbox.lty);
7056 bbox.rbx = ABS_X(bbox.rbx); bbox.rby = ABS_Y(bbox.rby);
7057 SetBBRec(&new_bbox, bbox.ltx+abs_dx, bbox.lty+abs_dy, bbox.rbx+abs_dx,
7058 bbox.rby+abs_dy);
7059 InflateBBox(&bbox, -(curTextOutlineHalfW<<1), -(curTextOutlineHalfW<<1),
7060 &bbox);
7061
7062 DoMoveEditText(dx, dy);
7063
7064 RedrawAreas(botObj, bbox.ltx-GRID_ABS_SIZE(2), bbox.lty-GRID_ABS_SIZE(2),
7065 bbox.rbx+GRID_ABS_SIZE(2), bbox.rby+GRID_ABS_SIZE(2),
7066 new_bbox.ltx-GRID_ABS_SIZE(2), new_bbox.lty-GRID_ABS_SIZE(2),
7067 new_bbox.rbx+GRID_ABS_SIZE(2), new_bbox.rby+GRID_ABS_SIZE(2));
7068 RedrawCurText();
7069 }
7070 ShowCurChoiceMouseStatus(curChoice, 0, FALSE);
7071 }
7072
MouseInCurText(input)7073 int MouseInCurText(input)
7074 XEvent *input;
7075 {
7076 if (curChoice == DRAWTEXT && textCursorShown) {
7077 int mouse_x=input->xbutton.x, mouse_y=input->xbutton.y;
7078 struct BBRec bbox;
7079
7080 GetCurTextBBoxes(NULL, &bbox);
7081 InflateBBox(&bbox, -(curTextOutlineHalfW<<1), -(curTextOutlineHalfW<<1),
7082 &bbox);
7083 if (PointInBBox(mouse_x, mouse_y, bbox)) {
7084 return TRUE;
7085 }
7086 }
7087 return FALSE;
7088 }
7089
MouseOnCurTextBoundary(input)7090 int MouseOnCurTextBoundary(input)
7091 XEvent *input;
7092 {
7093 if (MouseInCurText(input)) {
7094 int mouse_x=input->xbutton.x, mouse_y=input->xbutton.y;
7095 struct BBRec bbox;
7096
7097 GetCurTextBBoxes(NULL, &bbox);
7098 if (!PointInBBox(mouse_x, mouse_y, bbox)) {
7099 return TRUE;
7100 }
7101 }
7102 return FALSE;
7103 }
7104
MoveEditText(input)7105 void MoveEditText(input)
7106 XEvent *input;
7107 {
7108 if (MouseInCurText(input)) {
7109 ContinueMoveEditText(input->xbutton.x, input->xbutton.y);
7110 }
7111 }
7112
MoveEditTextBox()7113 void MoveEditTextBox()
7114 {
7115 unsigned int button;
7116 int mouse_x=0, mouse_y=0;
7117
7118 Msg(TgLoadString(STID_DRAG_MOUSE_MOVE_EDITTEXT_DOTS));
7119 SetMouseStatus(TgLoadCachedString(CSTID_START_MOVE_EDIT_TEXT_BOX),
7120 TgLoadCachedString(CSTID_CANCEL), TgLoadCachedString(CSTID_CANCEL));
7121 button = DrawWindowLoop(&mouse_x, &mouse_y, handCursor, FALSE);
7122 if (button == Button1) {
7123 ContinueMoveEditText(mouse_x, mouse_y);
7124 } else {
7125 Msg(TgLoadString(STID_MOVE_EDIT_TEXT_BOX_ABORTED));
7126 }
7127 }
7128