- Timestamp:
- Mar 9, 2011 3:28:24 PM (13 years ago)
- Location:
- trunk/gui/src
- Files:
-
- 1 added
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/gui/src/RpDiffview.c
r2119 r2125 3 3 * RpDiffview - like a textbox, but for showing diffs 4 4 * 5 * Loads two strings, performs a diff, and shows the results. 5 * Loads two strings, performs a diff, and shows the results. Use 6 * it as follows: 7 * 8 * Rappture::Diffview .dv \ 9 * -addedbackground blue -addedforeground white \ 10 * -deletedbackground red -deletedforeground white -overstrike true \ 11 * -changedbackground black -changedforeground yellow \ 12 * -xscrollcommand {.x set} -yscrollcommand {.y set} 13 * 14 * scrollbar .x -orient horizontal -command {.dv xview} 15 * scrollbar .y -orient vertical -command {.dv yview} 16 * 17 * .dv text 1 [exec cat /tmp/file1] 18 * .dv text 2 [exec cat /tmp/file2] 19 * .dv configure -diff 2->1 -layout sidebyside 20 * 21 * puts "DIFF OUTPUT:" 22 * puts [.dv diffs -std] 23 * 6 24 * ====================================================================== 7 25 * AUTHOR: Michael McLennan, Purdue University … … 14 32 #include "tk.h" 15 33 #include <string.h> 34 #include <stdlib.h> 16 35 17 36 /* … … 46 65 int numLines; /* number of lines */ 47 66 int maxLines; /* max size of storage in startPtr/endPtr */ 48 int maxWidth; /* max length in pixels for all lines */49 67 char **startPtr; /* array of start pointers for each line */ 50 68 int *lenPtr; /* array of lengths for each line */ … … 77 95 int fromIndex2; /* starts at this line in buffer 2 */ 78 96 int toIndex2; /* ends at this line in buffer 2 */ 97 int fromWorld; /* starts at this line in world view */ 98 int toWorld; /* ends at this line in world view */ 79 99 } DiffviewDiffOp; 80 100 … … 84 104 DiffviewDiffOp *ops; /* list of diffs */ 85 105 } DiffviewDiffs; 106 107 /* 108 * Data structure used for each line of the final layout: 109 */ 110 typedef struct { 111 char style; /* layout style: 'a'=add, 'd'=del, etc. */ 112 char bnum; /* show line from this buffer */ 113 int bline; /* line number in buffer bnum */ 114 int diffNum; /* line is part of this diff */ 115 } DiffviewLayoutLine; 116 117 typedef struct { 118 int maxLines; /* maximum number of lines allocated */ 119 int numLines; /* current number of lines in layout */ 120 DiffviewLayoutLine *lines; /* info for all lines in world view */ 121 } DiffviewLayout; 86 122 87 123 /* … … 109 145 DiffviewBuffer buffer[2]; /* text to diff -- buffers #1 and #2 */ 110 146 DiffviewDiffs *diffsPtr; /* diff: longest common subseq btwn buffers */ 111 112 enum diffdir diffdir; /* diff between these buffers */ 113 enum layoutStyle layout; /* layout style (side-by-side or inline) */ 114 int maxWidth; /* maximum width of world view in pixels */ 115 int maxHeight; /* maximum height of world view in pixels */ 116 int lineHeight; /* height of a line with current font */ 117 int lineAscent; /* ascent of a line with current font */ 118 int topLine; /* index of topmost line in view */ 119 int btmLine; /* index of bottommost line in view */ 120 int fullLines; /* number of full lines that fit in view */ 121 122 int xOffset; /* offset in pixels to left edge of view */ 123 int xScrollUnit; /* num pixels for one unit of horizontal 124 * scrolling (one average character) */ 125 int yOffset; /* offset in pixels to top edge of view */ 126 int yScrollUnit; /* num pixels for one unit of vertical 127 * scrolling (one average line) */ 147 DiffviewLayout worldview; /* array mapping each real line in world 148 * coordinates to the corresponding line 149 * in buffer #1/#2, along with its style */ 150 151 enum diffdir diffdir; /* diff between these buffers */ 152 enum layoutStyle layout; /* layout style (side-by-side or inline) */ 153 int maxWidth; /* maximum width of world view in pixels */ 154 int maxHeight; /* maximum height of world view in pixels */ 155 int lineHeight; /* height of a line with current font */ 156 int lineAscent; /* ascent of a line with current font */ 157 int topLine; /* index of topmost line in view */ 158 int btmLine; /* index of bottommost line in view */ 159 int fullLines; /* number of full lines that fit in view */ 160 161 int xOffset; /* offset in pixels to left edge of view */ 162 int xScrollUnit; /* num pixels for one unit of horizontal 163 * scrolling (one average character) */ 164 int yOffset; /* offset in pixels to top edge of view */ 165 int yScrollUnit; /* num pixels for one unit of vertical 166 * scrolling (one average line) */ 128 167 char *takeFocus; /* value of -takefocus option */ 129 168 char *yScrollCmd; /* command prefix for scrolling */ 130 169 char *xScrollCmd; /* command prefix for scrolling */ 131 170 132 int scanMarkX; 133 int scanMarkY; 134 int scanMarkXStart; 135 int scanMarkYStart; 171 int scanMarkX; /* x-coord for "scan mark" */ 172 int scanMarkY; /* y-coord for "scan mark" */ 173 int scanMarkXStart; /* xOffset at start of scan */ 174 int scanMarkYStart; /* yOffset at start of scan */ 136 175 137 176 … … 139 178 Tk_Font tklastfont; /* previous text font (so we detect changes) */ 140 179 XColor *fgColorPtr; /* normal foreground color */ 141 GC textGC; /* GC for drawing text */ 180 XColor *addBgColorPtr; /* background for "added" text in diff */ 181 XColor *addFgColorPtr; /* foreground for "added" text in diff */ 182 XColor *delBgColorPtr; /* background for "deleted" text in diff */ 183 XColor *delFgColorPtr; /* foreground for "deleted" text in diff */ 184 XColor *chgBgColorPtr; /* background for "changed" text in diff */ 185 XColor *chgFgColorPtr; /* foreground for "changed" text in diff */ 186 int overStrDel; /* non-zero => overstrike deleted text */ 187 GC normGC; /* GC for drawing normal text */ 188 GC addFgGC; /* GC for drawing "added" text in diff */ 189 GC delFgGC; /* GC for drawing "deleted" text in diff */ 190 GC chgFgGC; /* GC for drawing "changed" text in diff */ 142 191 int width; /* overall width of widget, in pixels */ 143 192 int height; /* overall height of widget, in pixels */ … … 172 221 #define NORMAL_BG "#d9d9d9" 173 222 223 #define DEF_DIFFVIEW_ADDBG "#ccffcc" 224 #define DEF_DIFFVIEW_ADDFG BLACK 174 225 #define DEF_DIFFVIEW_BG_COLOR NORMAL_BG 175 226 #define DEF_DIFFVIEW_BG_MONO WHITE 176 227 #define DEF_DIFFVIEW_BORDERWIDTH "2" 228 #define DEF_DIFFVIEW_CHGBG "#ffffcc" 229 #define DEF_DIFFVIEW_CHGFG BLACK 177 230 #define DEF_DIFFVIEW_CURSOR "" 231 #define DEF_DIFFVIEW_DELBG "#ffcccc" 232 #define DEF_DIFFVIEW_DELFG "#666666" 178 233 #define DEF_DIFFVIEW_DIFF "1->2" 179 234 #define DEF_DIFFVIEW_FG BLACK 180 #define DEF_DIFFVIEW_FONT " *-Helvetica-Medium-R-Normal-*-12-120-*"235 #define DEF_DIFFVIEW_FONT "Courier -12" 181 236 #define DEF_DIFFVIEW_HEIGHT "2i" 182 237 #define DEF_DIFFVIEW_HIGHLIGHT_BG NORMAL_BG … … 184 239 #define DEF_DIFFVIEW_HIGHLIGHT_WIDTH "1" 185 240 #define DEF_DIFFVIEW_LAYOUT "inline" 241 #define DEF_DIFFVIEW_OVERSTRDEL "true" 186 242 #define DEF_DIFFVIEW_RELIEF "sunken" 187 243 #define DEF_DIFFVIEW_TAKE_FOCUS (char*)NULL … … 194 250 */ 195 251 static Tk_OptionSpec optionSpecs[] = { 252 {TK_OPTION_COLOR, "-addedbackground", "addedBackground", "Background", 253 DEF_DIFFVIEW_ADDBG, -1, Tk_Offset(Diffview, addBgColorPtr), 254 TK_OPTION_NULL_OK, 0, 0}, 255 {TK_OPTION_COLOR, "-addedforeground", "addedForeground", "Foreground", 256 DEF_DIFFVIEW_ADDFG, -1, Tk_Offset(Diffview, addFgColorPtr), 257 TK_OPTION_NULL_OK, 0, 0}, 196 258 {TK_OPTION_BORDER, "-background", "background", "Background", 197 259 DEF_DIFFVIEW_BG_COLOR, -1, Tk_Offset(Diffview, normalBorder), … … 204 266 DEF_DIFFVIEW_BORDERWIDTH, -1, Tk_Offset(Diffview, borderWidth), 205 267 0, 0, 0}, 268 {TK_OPTION_COLOR, "-changedbackground", "changedBackground", "Background", 269 DEF_DIFFVIEW_CHGBG, -1, Tk_Offset(Diffview, chgBgColorPtr), 270 TK_OPTION_NULL_OK, 0, 0}, 271 {TK_OPTION_COLOR, "-changedforeground", "changedForeground", "Foreground", 272 DEF_DIFFVIEW_CHGFG, -1, Tk_Offset(Diffview, chgFgColorPtr), 273 TK_OPTION_NULL_OK, 0, 0}, 206 274 {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor", 207 275 DEF_DIFFVIEW_CURSOR, -1, Tk_Offset(Diffview, cursor), 276 TK_OPTION_NULL_OK, 0, 0}, 277 {TK_OPTION_COLOR, "-deletedbackground", "deletedBackground", "Background", 278 DEF_DIFFVIEW_DELBG, -1, Tk_Offset(Diffview, delBgColorPtr), 279 TK_OPTION_NULL_OK, 0, 0}, 280 {TK_OPTION_COLOR, "-deletedforeground", "deletedForeground", "Foreground", 281 DEF_DIFFVIEW_DELFG, -1, Tk_Offset(Diffview, delFgColorPtr), 208 282 TK_OPTION_NULL_OK, 0, 0}, 209 283 {TK_OPTION_STRING_TABLE, "-diff", "diff", "Diff", … … 230 304 DEF_DIFFVIEW_LAYOUT, -1, Tk_Offset(Diffview, layout), 231 305 0, (ClientData)layoutStyleStrings, 0}, 306 {TK_OPTION_BOOLEAN, "-overstrike", "overstrike", "Overstrike", 307 DEF_DIFFVIEW_OVERSTRDEL, -1, Tk_Offset(Diffview, overStrDel), 0, 0, 0}, 232 308 {TK_OPTION_RELIEF, "-relief", "relief", "Relief", 233 309 DEF_DIFFVIEW_RELIEF, -1, Tk_Offset(Diffview, relief), 0, 0, 0}, … … 273 349 Tcl_Obj *CONST objv[])); 274 350 static int DiffviewBboxSubCmd _ANSI_ARGS_ ((Tcl_Interp *interp, 275 Diffview *dvPtr, int index));351 Diffview *dvPtr, int objc, Tcl_Obj *CONST objv[])); 276 352 static int DiffviewDiffsSubCmd _ANSI_ARGS_ ((Tcl_Interp *interp, 277 353 Diffview *dvPtr, int objc, Tcl_Obj *CONST objv[])); … … 282 358 static int DiffviewYviewSubCmd _ANSI_ARGS_ ((Tcl_Interp *interp, 283 359 Diffview *dvPtr, int objc, Tcl_Obj *CONST objv[])); 360 static int DiffviewGetIndex _ANSI_ARGS_ ((Tcl_Interp *interp, 361 Diffview *dvPtr, Tcl_Obj *objPtr, int *linePtr, 362 DiffviewDiffOp **diffOpPtrPtr)); 284 363 285 364 static void DestroyDiffview _ANSI_ARGS_((char *memPtr)); … … 319 398 static void DiffviewDiffsFree _ANSI_ARGS_(( 320 399 DiffviewDiffs *diffsPtr)); 400 static void DiffviewLayoutAdd _ANSI_ARGS_(( 401 DiffviewLayout *layoutPtr, 402 DiffviewLayoutLine *linePtr)); 403 static void DiffviewLayoutClear _ANSI_ARGS_(( 404 DiffviewLayout *layoutPtr)); 405 static void DiffviewLayoutFree _ANSI_ARGS_(( 406 DiffviewLayout *layoutPtr)); 321 407 322 408 /* … … 410 496 dvPtr->cursor = None; 411 497 dvPtr->relief = TK_RELIEF_SUNKEN; 412 dvPtr->textGC = None; 498 dvPtr->normGC = None; 499 dvPtr->addFgGC = None; 500 dvPtr->delFgGC = None; 501 dvPtr->chgFgGC = None; 413 502 dvPtr->xScrollUnit = 1; 414 503 dvPtr->yScrollUnit = 1; … … 460 549 Diffview *dvPtr = (Diffview*)clientData; 461 550 int result = TCL_OK; 462 int cmdToken , index;551 int cmdToken; 463 552 464 553 if (objc < 2) { … … 482 571 switch (cmdToken) { 483 572 case COMMAND_BBOX: { 484 if (objc != 3) { 485 Tcl_WrongNumArgs(interp, 2, objv, "index"); 486 result = TCL_ERROR; 487 break; 488 } 489 result = Tcl_GetIntFromObj(interp, objv[2], &index); 490 if (result != TCL_OK) { 491 break; 492 } 493 result = DiffviewBboxSubCmd(interp, dvPtr, index); 573 result = DiffviewBboxSubCmd(interp, dvPtr, objc, objv); 494 574 break; 495 575 } … … 579 659 580 660 case COMMAND_SEE: { 581 int maxLines; 661 DiffviewDiffOp *diffOpPtr; 662 int line1, line2, topline; 663 582 664 if (objc != 3) { 583 665 Tcl_WrongNumArgs(interp, 2, objv, "index"); … … 585 667 break; 586 668 } 587 result = Tcl_GetIntFromObj(interp, objv[2], &index); 669 result = DiffviewGetIndex(interp, dvPtr, objv[2], 670 &line1, &diffOpPtr); 588 671 if (result != TCL_OK) { 589 672 break; 590 673 } 591 674 592 maxLines = dvPtr->maxHeight/dvPtr->lineHeight; 593 if (index >= maxLines) { 594 index = maxLines-1; 595 } 596 if (index < 0) { 597 index = 0; 598 } 599 600 if (index < dvPtr->topLine || index > dvPtr->btmLine) { 675 if (line1 < 0 && diffOpPtr != NULL) { 676 line1 = diffOpPtr->fromWorld; 677 line2 = diffOpPtr->toWorld; 678 } else { 679 line2 = line1; 680 } 681 682 if (line1 >= dvPtr->worldview.numLines) { 683 line1 = line2 = dvPtr->worldview.numLines-1; 684 } 685 if (line1 < 0) { 686 line1 = line2 = 0; 687 } 688 689 if (line1 < dvPtr->topLine || line1 > dvPtr->btmLine) { 601 690 /* location off screen? then center it in y-view */ 602 index -= dvPtr->fullLines/2; 603 if (index < 0) { 604 index = 0; 691 if (line2-line1 >= dvPtr->fullLines) { 692 topline = line1; 693 } else { 694 topline = (line1+line2)/2 - dvPtr->fullLines/2; 695 if (topline < 0) topline = 0; 605 696 } 606 ChangeDiffviewView(dvPtr, index);697 ChangeDiffviewView(dvPtr, topline); 607 698 } 608 699 result = TCL_OK; … … 640 731 */ 641 732 static int 642 DiffviewBboxSubCmd(interp, dvPtr, index)733 DiffviewBboxSubCmd(interp, dvPtr, objc, objv) 643 734 Tcl_Interp *interp; /* interp handling this command */ 644 735 Diffview *dvPtr; /* widget data */ 645 int index; /* desired element for bounding box */ 646 { 647 #ifdef FOO 648 int lastVisibleIndex; 649 /* Determine the index of the last visible item in the listbox */ 650 lastVisibleIndex = dvPtr->topIndex + dvPtr->fullLines 651 + dvPtr->partialLine; 652 if (dvPtr->nElements < lastVisibleIndex) { 653 lastVisibleIndex = dvPtr->nElements; 654 } 655 656 /* Only allow bbox requests for indices that are visible */ 657 if ((dvPtr->topIndex <= index) && (index < lastVisibleIndex)) { 658 char buf[TCL_INTEGER_SPACE * 4]; 659 Tcl_Obj *el; 660 char *stringRep; 661 int pixelWidth, stringLen, x, y, result; 662 Tk_FontMetrics fm; 663 664 /* Compute the pixel width of the requested element */ 665 result = Tcl_ListObjIndex(interp, dvPtr->listObj, index, &el); 666 if (result != TCL_OK) { 667 return result; 668 } 669 670 stringRep = Tcl_GetStringFromObj(el, &stringLen); 671 Tk_GetFontMetrics(dvPtr->tkfont, &fm); 672 pixelWidth = Tk_TextWidth(dvPtr->tkfont, stringRep, stringLen); 673 674 x = dvPtr->inset - dvPtr->xOffset; 675 y = ((index - dvPtr->topIndex)*dvPtr->lineHeight) + dvPtr->inset; 676 sprintf(buf, "%d %d %d %d", x, y, pixelWidth, fm.linespace); 736 int objc; /* number of command arguments */ 737 Tcl_Obj *CONST objv[]; /* command arguments */ 738 { 739 char *opt, buf[256]; 740 DiffviewDiffOp *diffOpPtr; 741 int line, bnum, bline, x1, y0, y1, wd; 742 char *textPtr; int textLen; 743 744 if (objc != 3) { 745 Tcl_WrongNumArgs(interp, 2, objv, "index"); 746 return TCL_ERROR; 747 } 748 749 /* make sure that our layout info is up to date for queries below */ 750 DiffviewUpdateLayout(dvPtr); 751 752 opt = Tcl_GetString(objv[2]); 753 if (*opt == 'a' && strcmp(opt,"all") == 0) { 754 sprintf(buf, "0 0 %d %d", dvPtr->maxWidth, dvPtr->maxHeight); 677 755 Tcl_SetResult(interp, buf, TCL_VOLATILE); 678 } 679 #endif 756 return TCL_OK; 757 } 758 759 if (DiffviewGetIndex(interp, dvPtr, objv[2], &line, &diffOpPtr) != TCL_OK) { 760 Tcl_AppendResult(interp, " or all", (char*)NULL); 761 return TCL_ERROR; 762 } 763 764 /* return the bounding box for a line in world coords */ 765 if (line >= 0) { 766 y0 = line*dvPtr->lineHeight; 767 y1 = (line+1)*dvPtr->lineHeight; 768 x1 = 0; 769 if (line < dvPtr->worldview.numLines) { 770 bnum = dvPtr->worldview.lines[line].bnum; 771 bline = dvPtr->worldview.lines[line].bline; 772 if (bline >= 0) { 773 textPtr = dvPtr->buffer[bnum].lineLimits->startPtr[bline]; 774 textLen = dvPtr->buffer[bnum].lineLimits->lenPtr[bline]; 775 x1 = Tk_TextWidth(dvPtr->tkfont, textPtr, textLen); 776 } 777 } 778 sprintf(buf, "0 %d %d %d", y0, x1, y1); 779 Tcl_SetResult(interp, buf, TCL_VOLATILE); 780 return TCL_OK; 781 } 782 783 /* return the bounding box for a diff in world coords */ 784 if (diffOpPtr) { 785 y0 = diffOpPtr->fromWorld*dvPtr->lineHeight; 786 y1 = (diffOpPtr->toWorld+1)*dvPtr->lineHeight; 787 x1 = 0; 788 789 for (line=diffOpPtr->fromWorld; line <= diffOpPtr->toWorld; line++) { 790 if (line < dvPtr->worldview.numLines) { 791 bnum = dvPtr->worldview.lines[line].bnum; 792 bline = dvPtr->worldview.lines[line].bline; 793 if (bline >= 0) { 794 textPtr = dvPtr->buffer[bnum].lineLimits->startPtr[bline]; 795 textLen = dvPtr->buffer[bnum].lineLimits->lenPtr[bline]; 796 wd = Tk_TextWidth(dvPtr->tkfont, textPtr, textLen); 797 if (wd > x1) { 798 x1 = wd; 799 } 800 } 801 } 802 } 803 sprintf(buf, "0 %d %d %d", y0, x1, y1); 804 Tcl_SetResult(interp, buf, TCL_VOLATILE); 805 } 680 806 return TCL_OK; 681 807 } … … 1125 1251 /* 1126 1252 * ---------------------------------------------------------------------- 1253 * DiffviewGetIndex() 1254 * 1255 * Used by many of the widget operations to parse an index into the 1256 * widget view. Handles the following syntax: 1257 * #NN ...... particular diff number, starting from 1 1258 * NN ....... particular line number in world view, starting from 0 1259 * 1260 * Returns TCL_OK if successful, and TCL_ERROR (along with an error 1261 * message) if anything goes wrong. 1262 * ---------------------------------------------------------------------- 1263 */ 1264 static int 1265 DiffviewGetIndex(interp, dvPtr, objPtr, linePtr, diffOpPtrPtr) 1266 Tcl_Interp *interp; /* interp handling this command */ 1267 Diffview *dvPtr; /* widget data */ 1268 Tcl_Obj *objPtr; /* argument being parsed */ 1269 int *linePtr; /* returns: line number or -1 */ 1270 DiffviewDiffOp **diffOpPtrPtr; /* returns: specific diff or NULL */ 1271 { 1272 int result = TCL_OK; 1273 char *opt = Tcl_GetString(objPtr); 1274 char *tail; 1275 int dnum; 1276 1277 /* clear the return values */ 1278 if (linePtr) *linePtr = -1; 1279 if (diffOpPtrPtr) *diffOpPtrPtr = NULL; 1280 1281 if (*opt == '#') { 1282 dnum = strtol(opt+1, &tail, 10); 1283 if (*tail != '\0' || dnum <= 0) { 1284 result = TCL_ERROR; 1285 } 1286 else if (dvPtr->diffsPtr == NULL 1287 || dnum > dvPtr->diffsPtr->numDiffs) { 1288 Tcl_AppendResult(interp, "diff \"", opt, "\" doesn't exist", 1289 (char*)NULL); 1290 return TCL_ERROR; 1291 } 1292 *diffOpPtrPtr = &dvPtr->diffsPtr->ops[dnum-1]; 1293 } else { 1294 result = Tcl_GetIntFromObj(interp, objPtr, linePtr); 1295 } 1296 1297 if (result != TCL_OK) { 1298 Tcl_ResetResult(interp); 1299 Tcl_AppendResult(interp, "bad index \"", opt, "\": should be " 1300 "\"#n\" for diff, or an integer value for line number", 1301 (char*)NULL); 1302 } 1303 return result; 1304 } 1305 1306 /* 1307 * ---------------------------------------------------------------------- 1127 1308 * DestroyDiffview() 1128 1309 * … … 1154 1335 DiffviewDiffsFree(dvPtr->diffsPtr); 1155 1336 } 1337 DiffviewLayoutFree(&dvPtr->worldview); 1156 1338 1157 1339 /* 1158 1340 * Free up GCs and configuration options. 1159 1341 */ 1160 if (dvPtr->textGC != None) { 1161 Tk_FreeGC(dvPtr->display, dvPtr->textGC); 1162 } 1342 if (dvPtr->normGC != None) { 1343 Tk_FreeGC(dvPtr->display, dvPtr->normGC); 1344 } 1345 if (dvPtr->addFgGC != None) { 1346 Tk_FreeGC(dvPtr->display, dvPtr->addFgGC); 1347 } 1348 if (dvPtr->delFgGC != None) { 1349 Tk_FreeGC(dvPtr->display, dvPtr->delFgGC); 1350 } 1351 if (dvPtr->chgFgGC != None) { 1352 Tk_FreeGC(dvPtr->display, dvPtr->chgFgGC); 1353 } 1354 1163 1355 Tk_FreeConfigOptions((char*)dvPtr, dvPtr->optionTable, dvPtr->tkwin); 1164 1356 Tcl_Release((ClientData) dvPtr->tkwin); … … 1240 1432 unsigned long mask; 1241 1433 1434 /* GC for normal widget text */ 1242 1435 gcValues.foreground = dvPtr->fgColorPtr->pixel; 1243 1436 gcValues.graphics_exposures = False; … … 1246 1439 1247 1440 gc = Tk_GetGC(dvPtr->tkwin, mask, &gcValues); 1248 if (dvPtr->textGC != None) { 1249 Tk_FreeGC(dvPtr->display, dvPtr->textGC); 1250 } 1251 dvPtr->textGC = gc; 1441 if (dvPtr->normGC != None) { 1442 Tk_FreeGC(dvPtr->display, dvPtr->normGC); 1443 } 1444 dvPtr->normGC = gc; 1445 1446 /* GC for added diff text */ 1447 gcValues.foreground = dvPtr->addFgColorPtr->pixel; 1448 gcValues.graphics_exposures = False; 1449 gcValues.font = Tk_FontId(dvPtr->tkfont); 1450 mask = GCForeground | GCFont | GCGraphicsExposures; 1451 1452 gc = Tk_GetGC(dvPtr->tkwin, mask, &gcValues); 1453 if (dvPtr->addFgGC != None) { 1454 Tk_FreeGC(dvPtr->display, dvPtr->addFgGC); 1455 } 1456 dvPtr->addFgGC = gc; 1457 1458 /* GC for deleted diff text */ 1459 gcValues.foreground = dvPtr->delFgColorPtr->pixel; 1460 gcValues.graphics_exposures = False; 1461 gcValues.font = Tk_FontId(dvPtr->tkfont); 1462 mask = GCForeground | GCFont | GCGraphicsExposures; 1463 1464 gc = Tk_GetGC(dvPtr->tkwin, mask, &gcValues); 1465 if (dvPtr->delFgGC != None) { 1466 Tk_FreeGC(dvPtr->display, dvPtr->delFgGC); 1467 } 1468 dvPtr->delFgGC = gc; 1469 1470 /* GC for changed diff text */ 1471 gcValues.foreground = dvPtr->chgFgColorPtr->pixel; 1472 gcValues.graphics_exposures = False; 1473 gcValues.font = Tk_FontId(dvPtr->tkfont); 1474 mask = GCForeground | GCFont | GCGraphicsExposures; 1475 1476 gc = Tk_GetGC(dvPtr->tkwin, mask, &gcValues); 1477 if (dvPtr->chgFgGC != None) { 1478 Tk_FreeGC(dvPtr->display, dvPtr->chgFgGC); 1479 } 1480 dvPtr->chgFgGC = gc; 1481 1482 /* this call comes when the font changes -- fix the layout */ 1483 dvPtr->flags |= FONT_CHANGED; 1252 1484 1253 1485 /* get ready to redraw */ … … 1291 1523 Tk_Window tkwin = dvPtr->tkwin; 1292 1524 1293 int i, bnum, x, y;1525 int i, bnum, bline, x, xw, y, ymid, width; 1294 1526 char *textPtr; int textLen; 1295 1527 Pixmap pixmap; 1528 GC bg, fg; 1296 1529 1297 1530 /* handling redraw now -- no longer pending */ … … 1350 1583 - dvPtr->yOffset; 1351 1584 x = dvPtr->inset - dvPtr->xOffset; 1352 1353 if (dvPtr->diffdir == DIFF_1TO2) { 1354 bnum = 1; /* 1->2 means: show lines from buffer #2 */ 1355 } else { 1356 bnum = 0; /* 2->1 means: show lines from buffer #1 */ 1357 } 1358 1359 if (dvPtr->buffer[bnum].lineLimits) { 1360 for (i=dvPtr->topLine; i <= dvPtr->btmLine; i++) { 1361 if (i >= dvPtr->buffer[bnum].lineLimits->numLines) { 1585 width = Tk_Width(tkwin); 1586 1587 for (i=dvPtr->topLine; 1588 i <= dvPtr->btmLine && i < dvPtr->worldview.numLines; 1589 i++) { 1590 1591 /* draw any diff rectangle for this line */ 1592 fg = dvPtr->normGC; 1593 bg = None; 1594 1595 switch (dvPtr->worldview.lines[i].style) { 1596 case 'a': { 1597 fg = dvPtr->addFgGC; 1598 bg = Tk_GCForColor(dvPtr->addBgColorPtr, pixmap); 1362 1599 break; 1363 1600 } 1364 1365 /* draw any diff rectangle for this line */ 1366 /* 1367 Tk_Fill3DRectangle(tkwin, pixmap, selectedBg, x, y, 1368 width, dvPtr->lineHeight, 0, TK_RELIEF_FLAT); 1369 */ 1370 1371 textPtr = dvPtr->buffer[bnum].lineLimits->startPtr[i]; 1372 textLen = dvPtr->buffer[bnum].lineLimits->lenPtr[i]; 1601 case 'd': { 1602 fg = dvPtr->delFgGC; 1603 bg = Tk_GCForColor(dvPtr->delBgColorPtr, pixmap); 1604 break; 1605 } 1606 case 'c': { 1607 fg = dvPtr->chgFgGC; 1608 bg = Tk_GCForColor(dvPtr->chgBgColorPtr, pixmap); 1609 break; 1610 } 1611 } 1612 1613 if (bg != None) { 1614 XFillRectangle(Tk_Display(tkwin), pixmap, bg, 1615 x, y - dvPtr->lineAscent, 1616 (unsigned int)width, (unsigned int)dvPtr->lineHeight); 1617 } 1618 1619 bnum = dvPtr->worldview.lines[i].bnum; 1620 bline = dvPtr->worldview.lines[i].bline; 1621 1622 /* a negative number means "leave the line blank" */ 1623 if (bline >= 0) { 1624 textPtr = dvPtr->buffer[bnum].lineLimits->startPtr[bline]; 1625 textLen = dvPtr->buffer[bnum].lineLimits->lenPtr[bline]; 1373 1626 1374 1627 /* Draw the actual text of this item */ 1375 Tk_DrawChars(dvPtr->display, pixmap, dvPtr->textGC, dvPtr->tkfont, 1376 textPtr, textLen, x, y); 1377 1378 y += dvPtr->lineHeight; 1379 } 1628 Tk_DrawChars(dvPtr->display, pixmap, fg, dvPtr->tkfont, 1629 textPtr, textLen, x, y); 1630 1631 /* Draw an overstrike on deleted text */ 1632 if (dvPtr->worldview.lines[i].style == 'd' && dvPtr->overStrDel) { 1633 xw = Tk_TextWidth(dvPtr->tkfont, textPtr, textLen) + 5; 1634 ymid = y - dvPtr->lineAscent/2; 1635 XDrawLine(Tk_Display(tkwin), pixmap, fg, 0, ymid, xw, ymid); 1636 } 1637 } 1638 1639 y += dvPtr->lineHeight; 1380 1640 } 1381 1641 … … 1401 1661 #ifndef TK_NO_DOUBLE_BUFFERING 1402 1662 XCopyArea(dvPtr->display, pixmap, Tk_WindowId(tkwin), 1403 dvPtr-> textGC, 0, 0, (unsigned) Tk_Width(tkwin),1663 dvPtr->normGC, 0, 0, (unsigned) Tk_Width(tkwin), 1404 1664 (unsigned) Tk_Height(tkwin), 0, 0); 1405 1665 Tk_FreePixmap(dvPtr->display, pixmap); … … 1611 1871 int changes = 0; /* no layout changes yet */ 1612 1872 DiffviewBuffer* bufferPtr; 1613 int i, bnum, pixelWidth, maxWidth, numLines, ySize; 1873 DiffviewDiffOp *currOp; 1874 DiffviewLayoutLine line; 1875 int i, bnum, bline, pixelWidth, maxWidth, ySize; 1876 int numLines1, numLines2, lnum1, lnum2, dnum, lastdnum, pastDiff; 1614 1877 char *textPtr, *textPtr2; int textLen; 1615 1878 Tk_FontMetrics fm; … … 1639 1902 textPtr = Tcl_GetStringFromObj(dvPtr->buffer[0].textObj, &textLen); 1640 1903 textPtr2 = Tcl_GetStringFromObj(dvPtr->buffer[1].textObj, &textLen); 1904 1641 1905 dvPtr->diffsPtr = DiffviewDiffsCreate( 1642 1906 textPtr, dvPtr->buffer[0].lineLimits, … … 1644 1908 } 1645 1909 1646 /* compute overall size of each buffer */ 1647 for (bnum=0; bnum < 2; bnum++) { 1648 bufferPtr = &dvPtr->buffer[bnum]; 1649 1650 if (bufferPtr->lineLimits) { 1651 maxWidth = 0; 1652 1653 for (i=0; i < bufferPtr->lineLimits->numLines; i++) { 1654 textPtr = bufferPtr->lineLimits->startPtr[i]; 1655 textLen = bufferPtr->lineLimits->lenPtr[i]; 1910 /* 1911 * Compute the layout of all lines according to the current 1912 * view mode. Each line in the world view is stored in the 1913 * array dvPtr->worldview.lines. Each line has a style (color 1914 * for normal, add, delete, etc.) and an indication of which 1915 * buffer it comes from. 1916 */ 1917 DiffviewLayoutClear(&dvPtr->worldview); 1918 1919 /* 1920 * March through the lines and figure out the source and style 1921 * of each line based on the diffs: 1922 * 'n' = normal (common) line 1923 * 'a' = draw with the "added" style 1924 * 'd' = draw with the "deleted" style 1925 * 'c' = draw with the "changed" style 1926 */ 1927 numLines1 = (dvPtr->buffer[0].lineLimits) 1928 ? dvPtr->buffer[0].lineLimits->numLines : 0; 1929 numLines2 = (dvPtr->buffer[1].lineLimits) 1930 ? dvPtr->buffer[1].lineLimits->numLines : 0; 1931 1932 dnum = 0; /* current difference in diffsPtr */ 1933 lnum1 = lnum2 = 0; 1934 1935 while (lnum1 < numLines1 || lnum2 < numLines2) { 1936 /* assume it's a normal-looking line (buffers are the same) */ 1937 line.style = 'n'; 1938 line.bnum = 0; 1939 line.bline = lnum1; 1940 line.diffNum = -1; 1941 1942 /* is there a diff that contains this line? */ 1943 if (dvPtr->diffsPtr && dnum < dvPtr->diffsPtr->numDiffs) { 1944 currOp = &dvPtr->diffsPtr->ops[dnum]; 1945 1946 if ( (lnum1 >= currOp->fromIndex1 1947 && lnum1 <= currOp->toIndex1) 1948 || (lnum2 >= currOp->fromIndex2 1949 && lnum2 <= currOp->toIndex2) ) { 1950 1951 line.diffNum = dnum; /* line is part of this diff */ 1952 1953 switch (currOp->op) { 1954 case 'c': { 1955 if (dvPtr->layout == LAYOUT_INLINE) { 1956 if (dvPtr->diffdir == DIFF_1TO2) { 1957 /* show the buffer #1 lines first, then #2 */ 1958 if (lnum1 <= currOp->toIndex1) { 1959 line.style = 'd'; 1960 line.bnum = 0; 1961 line.bline = lnum1++; 1962 } else { 1963 line.style = 'a'; 1964 line.bnum = 1; 1965 line.bline = lnum2++; 1966 } 1967 } else { 1968 /* reverse -- show #2 lines first, then #1 */ 1969 if (lnum2 <= currOp->toIndex2) { 1970 line.style = 'd'; 1971 line.bnum = 1; 1972 line.bline = lnum2++; 1973 } else { 1974 line.style = 'a'; 1975 line.bnum = 0; 1976 line.bline = lnum1++; 1977 } 1978 } 1979 } else { 1980 if (dvPtr->diffdir == DIFF_1TO2) { 1981 /* show final lines in buf #2 as "changed" */ 1982 line.style = 'c'; 1983 line.bnum = 1; 1984 line.bline = lnum2++; 1985 lnum1 = currOp->toIndex1+1; 1986 } else { 1987 /* show final lines in buf #1 as "changed" */ 1988 line.style = 'c'; 1989 line.bnum = 0; 1990 line.bline = lnum1++; 1991 lnum2 = currOp->toIndex2+1; 1992 } 1993 } 1994 break; 1995 } 1996 case 'a': { 1997 if (dvPtr->diffdir == DIFF_1TO2) { 1998 /* show lines in buffer #2 as 'added' */ 1999 line.style = 'a'; 2000 line.bnum = 1; 2001 line.bline = lnum2++; 2002 lnum1 = currOp->toIndex1; 2003 } else { 2004 /* reverse diff -- like we're deleting lines */ 2005 if (dvPtr->layout == LAYOUT_INLINE) { 2006 line.style = 'd'; 2007 line.bnum = 1; 2008 line.bline = lnum2++; 2009 lnum1 = currOp->toIndex1; 2010 } else { 2011 /* show lines from buffer #2 as empty */ 2012 line.style = 'd'; 2013 line.bnum = 0; 2014 line.bline = -1; 2015 lnum2++; 2016 lnum1 = currOp->toIndex1; 2017 } 2018 } 2019 break; 2020 } 2021 case 'd': { 2022 if (dvPtr->diffdir == DIFF_1TO2) { 2023 if (dvPtr->layout == LAYOUT_INLINE) { 2024 line.style = 'd'; 2025 line.bnum = 0; 2026 line.bline = lnum1++; 2027 lnum2 = currOp->toIndex2; 2028 } else { 2029 /* show lines from buffer #2 as empty */ 2030 line.style = 'd'; 2031 line.bnum = 0; 2032 line.bline = -1; 2033 lnum1++; 2034 lnum2 = currOp->toIndex2; 2035 } 2036 } else { 2037 /* reverse diff -- like we're adding lines */ 2038 line.style = 'a'; 2039 line.bnum = 0; 2040 line.bline = lnum1++; 2041 lnum2 = currOp->toIndex2; 2042 } 2043 break; 2044 } 2045 default: { 2046 Tcl_Panic("bad diff type '%c' found in layout", 2047 currOp->op); 2048 break; 2049 } 2050 } 2051 } else { 2052 /* normal line -- keep moving forward */ 2053 lnum1++; lnum2++; 2054 } 2055 2056 /* have we reached the end of the diff? then move on */ 2057 pastDiff = 0; 2058 switch (currOp->op) { 2059 case 'c': 2060 pastDiff = (lnum1 > currOp->toIndex1 2061 && lnum2 > currOp->toIndex2); 2062 break; 2063 case 'a': 2064 pastDiff = (lnum2 > currOp->toIndex2); 2065 break; 2066 case 'd': 2067 pastDiff = (lnum1 > currOp->toIndex1); 2068 break; 2069 } 2070 if (pastDiff) { 2071 dnum++; 2072 } 2073 } else { 2074 /* no more diffs -- keep moving forward */ 2075 lnum1++; lnum2++; 2076 } 2077 2078 /* add this new line to the layout */ 2079 DiffviewLayoutAdd(&dvPtr->worldview, &line); 2080 } 2081 2082 /* 2083 * Figure out where the diffs are located, and put that info 2084 * back into the diffs. This makes it easy later to refer to 2085 * diff "#3" and understand what lines we're talking about. 2086 */ 2087 lastdnum = -1; 2088 for (i=0; i < dvPtr->worldview.numLines; i++) { 2089 dnum = dvPtr->worldview.lines[i].diffNum; 2090 if (dnum != lastdnum) { 2091 if (lastdnum < 0) { 2092 /* leading edge -- catch the "from" line */ 2093 lnum1 = i; 2094 } else { 2095 /* trailing edge -- save diff info */ 2096 dvPtr->diffsPtr->ops[lastdnum].fromWorld = lnum1; 2097 dvPtr->diffsPtr->ops[lastdnum].toWorld = i-1; 2098 } 2099 } 2100 lastdnum = dnum; 2101 } 2102 if (lastdnum >= 0) { 2103 dvPtr->diffsPtr->ops[lastdnum].fromWorld = lnum1; 2104 dvPtr->diffsPtr->ops[lastdnum].toWorld = i-1; 2105 } 2106 2107 /* compute overall text width for all lines */ 2108 maxWidth = 0; 2109 for (i=0; i < dvPtr->worldview.numLines; i++) { 2110 bline = dvPtr->worldview.lines[i].bline; 2111 if (bline >= 0) { 2112 bnum = dvPtr->worldview.lines[i].bnum; 2113 bufferPtr = &dvPtr->buffer[bnum]; 2114 2115 if (bufferPtr->lineLimits) { 2116 textPtr = bufferPtr->lineLimits->startPtr[bline]; 2117 textLen = bufferPtr->lineLimits->lenPtr[bline]; 1656 2118 pixelWidth = Tk_TextWidth(dvPtr->tkfont, textPtr, textLen); 1657 2119 … … 1660 2122 } 1661 2123 } 1662 bufferPtr->lineLimits->maxWidth = maxWidth;1663 }1664 }1665 1666 /* compute overall size of the widget depending on the layout */1667 if (dvPtr->diffdir == DIFF_1TO2) {1668 bnum = 0;1669 } else {1670 bnum = 1;1671 }1672 1673 maxWidth = 0;1674 numLines = 0;1675 if (dvPtr->buffer[bnum].lineLimits) {1676 maxWidth = dvPtr->buffer[bnum].lineLimits->maxWidth;1677 if (dvPtr->layout == LAYOUT_INLINE) {1678 numLines = dvPtr->buffer[bnum].lineLimits->numLines;1679 } else {1680 /* WARNING - should compute the height by looking at diffs */1681 for (i=0; i < 2; i++) {1682 if (dvPtr->buffer[i].lineLimits1683 && dvPtr->buffer[i].lineLimits->numLines > numLines) {1684 numLines = dvPtr->buffer[i].lineLimits->numLines;1685 }1686 }1687 2124 } 1688 2125 } 1689 2126 dvPtr->maxWidth = maxWidth; 1690 2127 2128 /* compute overall height of the widget */ 1691 2129 Tk_GetFontMetrics(dvPtr->tkfont, &fm); 1692 2130 dvPtr->lineHeight = fm.linespace; 1693 2131 dvPtr->lineAscent = fm.ascent; 1694 dvPtr->maxHeight = numLines * fm.linespace;2132 dvPtr->maxHeight = dvPtr->worldview.numLines * fm.linespace; 1695 2133 1696 2134 /* figure out the limits of the current view */ … … 1840 2278 lineLimitsPtr = (DiffviewLines*)ckalloc(sizeof(DiffviewLines)); 1841 2279 lineLimitsPtr->maxLines = 0; 1842 lineLimitsPtr->maxWidth = 0;1843 2280 lineLimitsPtr->startPtr = NULL; 1844 2281 lineLimitsPtr->lenPtr = NULL; … … 2221 2658 * DiffviewDiffsFree() 2222 2659 * 2223 * Appends a "diff" operation onto a list of diffs. The list is extended2224 * automatically, if need be, to store the new element.2660 * Frees up the storage previously created by calling 2661 * DiffviewDiffsAppend(). 2225 2662 * ---------------------------------------------------------------------- 2226 2663 */ … … 2234 2671 ckfree((char*)diffsPtr); 2235 2672 } 2673 2674 /* 2675 * ---------------------------------------------------------------------- 2676 * DiffviewLayoutAdd() 2677 * 2678 * Clears out the layout storage in preparation for building another 2679 * layout. If the previous number of lines was much less than the 2680 * maximum allocated, then this routine reallocates a smaller storage 2681 * space. This provides a way to give back a large chunk of memory 2682 * if the contents of the widget is nulled out, for example. 2683 * ---------------------------------------------------------------------- 2684 */ 2685 static void 2686 DiffviewLayoutAdd(layoutPtr, linePtr) 2687 DiffviewLayout *layoutPtr; /* line layout being updated */ 2688 DiffviewLayoutLine *linePtr; /* line being added to layout */ 2689 { 2690 DiffviewLayoutLine *newLineArray; 2691 2692 /* expand the array as needed */ 2693 if (layoutPtr->numLines >= layoutPtr->maxLines) { 2694 if (layoutPtr->maxLines == 0) { 2695 layoutPtr->maxLines = 100; 2696 } else { 2697 layoutPtr->maxLines *= 2; 2698 } 2699 newLineArray = (DiffviewLayoutLine*)ckalloc( 2700 (unsigned)(layoutPtr->maxLines*sizeof(DiffviewLayoutLine))); 2701 2702 if (layoutPtr->lines) { 2703 memcpy((VOID*)newLineArray, (VOID*)layoutPtr->lines, 2704 layoutPtr->numLines*sizeof(DiffviewLayoutLine)); 2705 ckfree((char*)layoutPtr->lines); 2706 } 2707 layoutPtr->lines = newLineArray; 2708 } 2709 2710 /* copy the latest line in and bump the count */ 2711 memcpy((VOID*)&layoutPtr->lines[layoutPtr->numLines], 2712 (VOID*)linePtr, sizeof(DiffviewLayoutLine)); 2713 2714 layoutPtr->numLines++; 2715 } 2716 2717 /* 2718 * ---------------------------------------------------------------------- 2719 * DiffviewLayoutClear() 2720 * 2721 * Clears out the layout storage in preparation for building another 2722 * layout. If the previous number of lines was much less than the 2723 * maximum allocated, then this routine reallocates a smaller storage 2724 * space. This provides a way to give back a large chunk of memory 2725 * if the contents of the widget is nulled out, for example. 2726 * ---------------------------------------------------------------------- 2727 */ 2728 static void 2729 DiffviewLayoutClear(layoutPtr) 2730 DiffviewLayout *layoutPtr; /* line layout being freed */ 2731 { 2732 if (layoutPtr->numLines > 0 2733 && layoutPtr->numLines < layoutPtr->maxLines/3 2734 && layoutPtr->maxLines > 100) { 2735 ckfree((char*)layoutPtr->lines); 2736 layoutPtr->lines = (DiffviewLayoutLine*)ckalloc( 2737 (unsigned)(layoutPtr->numLines * sizeof(DiffviewLayoutLine))); 2738 } 2739 layoutPtr->numLines = 0; 2740 } 2741 2742 /* 2743 * ---------------------------------------------------------------------- 2744 * DiffviewLayoutFree() 2745 * 2746 * Frees the storage associated with the layout of all lines within 2747 * the widget. 2748 * ---------------------------------------------------------------------- 2749 */ 2750 static void 2751 DiffviewLayoutFree(layoutPtr) 2752 DiffviewLayout *layoutPtr; /* line layout being freed */ 2753 { 2754 if (layoutPtr->lines) { 2755 ckfree((char*)layoutPtr->lines); 2756 layoutPtr->lines = NULL; 2757 } 2758 }
Note: See TracChangeset
for help on using the changeset viewer.