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, &ltx, &lty);
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