1: /*************************************************************************** 2: * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE * 3: * is provided to you without charge, and with no warranty. You may give * 4: * away copies of JOVE, including sources, provided that this notice is * 5: * included in all the files. * 6: ***************************************************************************/ 7: 8: /* This creates/deletes/divides/grows/shrinks windows. */ 9: 10: #include "jove.h" 11: #include "termcap.h" 12: 13: private char onlyone[] = "You only have one window!", 14: toosmall[] = "Resulting window would be too small."; 15: 16: Window *curwind, 17: *fwind = 0; 18: 19: /* First line in a Window */ 20: 21: int 22: FLine(w) 23: register Window *w; 24: { 25: register Window *wp = fwind; 26: register int lineno = -1; 27: 28: do { 29: if (wp == w) 30: return lineno + 1; 31: lineno += wp->w_height; 32: wp = wp->w_next; 33: } while (wp != fwind); 34: complain("window?"); 35: /* NOTREACHED */ 36: } 37: 38: /* Delete `wp' from the screen. If it is the only window left 39: on the screen, then complain. It gives its body 40: to the next window if there is one, otherwise the previous 41: window gets the body. */ 42: 43: void 44: del_wind(wp) 45: register Window *wp; 46: { 47: register Window *prev = wp->w_prev; 48: 49: if (one_windp()) 50: complain(onlyone); 51: 52: wp->w_prev->w_next = wp->w_next; 53: wp->w_next->w_prev = wp->w_prev; 54: 55: if (fwind == wp) { 56: fwind = wp->w_next; 57: fwind->w_height += wp->w_height; 58: /* Here try to do something intelligent for redisplay() */ 59: SetTop(fwind, prev_line(fwind->w_top, wp->w_height)); 60: if (curwind == wp) 61: SetWind(fwind); 62: } else { 63: prev->w_height += wp->w_height; 64: if (curwind == wp) 65: SetWind(prev); 66: } 67: #ifdef MAC 68: RemoveScrollBar(wp); 69: Windchange++; 70: #endif 71: free((char *) wp); 72: } 73: 74: /* Divide the window WP N times, or at least once. Complains if WP is too 75: small to be split into that many pieces. It returns the new window. */ 76: 77: Window * 78: div_wind(wp, n) 79: register Window *wp; 80: { 81: register Window *new; 82: int amt; 83: 84: if (n < 1) 85: n = 1; 86: amt = wp->w_height / (n + 1); 87: if (amt < 2) 88: complain(toosmall); 89: 90: while (--n >= 0) { 91: new = (Window *) emalloc(sizeof (Window)); 92: new->w_flags = 0; 93: new->w_LRscroll = 0; 94: 95: new->w_height = amt; 96: wp->w_height -= amt; 97: 98: /* set the lines such that w_line is the center in 99: each Window */ 100: new->w_line = wp->w_line; 101: new->w_char = wp->w_char; 102: new->w_bufp = wp->w_bufp; 103: new->w_top = prev_line(new->w_line, HALF(new)); 104: 105: /* Link the new window into the list */ 106: new->w_prev = wp; 107: new->w_next = wp->w_next; 108: new->w_next->w_prev = new; 109: wp->w_next = new; 110: #ifdef MAC 111: new->w_control = 0; 112: #endif 113: } 114: #ifdef MAC 115: Windchange++; 116: #endif 117: return new; 118: } 119: 120: /* Initialze the first window setting the bounds to the size of the 121: screen. There is no buffer with this window. See parse for the 122: setting of this window. */ 123: 124: void 125: winit() 126: { 127: register Window *w; 128: 129: w = curwind = fwind = (Window *) emalloc(sizeof (Window)); 130: w->w_line = w->w_top = 0; 131: w->w_LRscroll = 0; 132: w->w_flags = 0; 133: w->w_char = 0; 134: w->w_next = w->w_prev = fwind; 135: w->w_height = ILI; 136: #ifdef MAC 137: w->w_control = 0; 138: Windchange++; 139: #endif 140: } 141: 142: /* Change to previous window. */ 143: 144: void 145: PrevWindow() 146: { 147: register Window *new = curwind->w_prev; 148: 149: if (Asking) 150: complain((char *) 0); 151: if (one_windp()) 152: complain(onlyone); 153: SetWind(new); 154: } 155: 156: /* Make NEW the current Window */ 157: 158: void 159: SetWind(new) 160: register Window *new; 161: { 162: if (!Asking) { /* can you say kludge? */ 163: curwind->w_line = curline; 164: curwind->w_char = curchar; 165: curwind->w_bufp = curbuf; 166: } 167: if (new == curwind) 168: return; 169: SetBuf(new->w_bufp); 170: if (!inlist(new->w_bufp->b_first, new->w_line)) { 171: new->w_line = curline; 172: new->w_char = curchar; 173: } 174: DotTo(new->w_line, new->w_char); 175: if (curchar > strlen(linebuf)) 176: new->w_char = curchar = strlen(linebuf); 177: curwind = new; 178: } 179: 180: /* delete the current window if it isn't the only one left */ 181: 182: void 183: DelCurWindow() 184: { 185: SetABuf(curwind->w_bufp); 186: del_wind(curwind); 187: } 188: 189: /* put the current line of `w' in the middle of the window */ 190: 191: void 192: CentWind(w) 193: register Window *w; 194: { 195: SetTop(w, prev_line(w->w_line, HALF(w))); 196: } 197: 198: int ScrollStep = 0; /* full scrolling */ 199: 200: /* Calculate the new topline of the window. If ScrollStep == 0 201: it means we should center the current line in the window. */ 202: 203: void 204: CalcWind(w) 205: register Window *w; 206: { 207: register int up; 208: int scr_step; 209: Line *newtop; 210: 211: if (ScrollStep == 0) /* Means just center it */ 212: CentWind(w); 213: else { 214: up = inorder(w->w_line, 0, w->w_top, 0); 215: if (up == -1) { 216: CentWind(w); 217: return; 218: } 219: scr_step = (ScrollStep < 0) ? SIZE(w) + ScrollStep : 220: ScrollStep - 1; 221: if (up) /* point is above the screen */ 222: newtop = prev_line(w->w_line, scr_step); 223: else 224: newtop = prev_line(w->w_line, (SIZE(w) - 1 - scr_step)); 225: if (LineDist(newtop, w->w_top) >= SIZE(w) - 1) 226: CentWind(w); 227: else 228: SetTop(w, newtop); 229: } 230: } 231: 232: /* This is bound to C-X 4 [BTF]. To make the screen stay the 233: same we have to remember various things, like the current 234: top line in the current window. It's sorta gross, but it's 235: necessary because of the way this is implemented (i.e., in 236: terms of do_find(), do_select() which manipulate the windows. */ 237: 238: void 239: WindFind() 240: { 241: register Buffer *obuf = curbuf, 242: *nbuf; 243: Line *ltop = curwind->w_top; 244: Bufpos savedot; 245: extern void 246: FindTag(), 247: BufSelect(), 248: FindFile(); 249: 250: DOTsave(&savedot); 251: 252: switch (waitchar((int *) 0)) { 253: case 't': 254: case 'T': 255: ExecCmd((data_obj *) FindCmd(FindTag)); 256: break; 257: 258: case 'b': 259: case 'B': 260: ExecCmd((data_obj *) FindCmd(BufSelect)); 261: break; 262: 263: case 'f': 264: case 'F': 265: ExecCmd((data_obj *) FindCmd(FindFile)); 266: break; 267: 268: default: 269: complain("T: find-tag, F: find-file, B: select-buffer."); 270: } 271: 272: nbuf = curbuf; 273: SetBuf(obuf); 274: SetDot(&savedot); 275: SetTop(curwind, ltop); /* there! it's as if we did nothing */ 276: 277: if (one_windp()) 278: (void) div_wind(curwind, 1); 279: 280: tiewind(curwind->w_next, nbuf); 281: SetWind(curwind->w_next); 282: } 283: 284: /* Go into one window mode by deleting all the other windows */ 285: 286: void 287: OneWindow() 288: { 289: while (curwind->w_next != curwind) 290: del_wind(curwind->w_next); 291: } 292: 293: Window * 294: windbp(bp) 295: register Buffer *bp; 296: { 297: 298: register Window *wp = fwind; 299: 300: if (bp == 0) 301: return 0; 302: do { 303: if (wp->w_bufp == bp) 304: return wp; 305: wp = wp->w_next; 306: } while (wp != fwind); 307: return 0; 308: } 309: 310: /* Change window into the next window. Curwind becomes the new window. */ 311: 312: void 313: NextWindow() 314: { 315: register Window *new = curwind->w_next; 316: 317: if (Asking) 318: complain((char *) 0); 319: if (one_windp()) 320: complain(onlyone); 321: SetWind(new); 322: } 323: 324: /* Scroll the next Window */ 325: 326: void 327: PageNWind() 328: { 329: if (one_windp()) 330: complain(onlyone); 331: NextWindow(); 332: NextPage(); 333: PrevWindow(); 334: } 335: 336: Window * 337: w_nam_typ(name, type) 338: register char *name; 339: { 340: register Window *w; 341: register Buffer *b; 342: 343: b = buf_exists(name); 344: w = fwind; 345: if (b) do { 346: if (w->w_bufp == b) 347: return w; 348: } while ((w = w->w_next) != fwind); 349: 350: w = fwind; 351: do { 352: if (w->w_bufp->b_type == type) 353: return w; 354: } while ((w = w->w_next) != fwind); 355: 356: return 0; 357: } 358: 359: /* Put a window with the buffer `name' in it. Erase the buffer if 360: `clobber' is non-zero. */ 361: 362: void 363: pop_wind(name, clobber, btype) 364: register char *name; 365: { 366: register Window *wp; 367: register Buffer *newb; 368: 369: if (newb = buf_exists(name)) 370: btype = -1; /* if the buffer exists, don't change 371: it's type */ 372: if ((wp = w_nam_typ(name, btype)) == 0) { 373: if (one_windp()) 374: SetWind(div_wind(curwind, 1)); 375: else 376: PrevWindow(); 377: } else 378: SetWind(wp); 379: 380: newb = do_select((Window *) 0, name); 381: if (clobber) { 382: initlist(newb); 383: newb->b_modified = NO; 384: } 385: tiewind(curwind, newb); 386: if (btype != -1) 387: newb->b_type = btype; 388: SetBuf(newb); 389: } 390: 391: void 392: GrowWindow() 393: { 394: WindSize(curwind, abs(arg_value())); 395: } 396: 397: void 398: ShrWindow() 399: { 400: WindSize(curwind, -abs(arg_value())); 401: } 402: 403: /* Change the size of the window by inc. First arg is the window, 404: second is the increment. */ 405: 406: void 407: WindSize(w, inc) 408: register Window *w; 409: register int inc; 410: { 411: if (one_windp()) 412: complain(onlyone); 413: 414: if (inc == 0) 415: return; 416: else if (inc < 0) { /* Shrinking this Window. */ 417: if (w->w_height + inc < 2) 418: complain(toosmall); 419: w->w_height += inc; 420: w->w_prev->w_height -= inc; 421: } else /* Growing the window. */ 422: WindSize(w->w_next, -inc); 423: #ifdef MAC 424: Windchange++; 425: #endif 426: } 427: 428: /* Set the topline of the window, calculating its number in the buffer. 429: This is for numbering the lines only. */ 430: 431: void 432: SetTop(w, line) 433: Window *w; 434: register Line *line; 435: { 436: register Line *lp = w->w_bufp->b_first; 437: register int num = 0; 438: 439: w->w_top = line; 440: if (w->w_flags & W_NUMLINES) { 441: while (lp) { 442: num += 1; 443: if (line == lp) 444: break; 445: lp = lp->l_next; 446: } 447: w->w_topnum = num; 448: } 449: } 450: 451: void 452: WNumLines() 453: { 454: curwind->w_flags ^= W_NUMLINES; 455: SetTop(curwind, curwind->w_top); 456: } 457: 458: void 459: WVisSpace() 460: { 461: curwind->w_flags ^= W_VISSPACE; 462: ClAndRedraw(); 463: } 464: 465: /* Return the line number that `line' occupies in `windes' */ 466: 467: int 468: in_window(windes, line) 469: register Window *windes; 470: register Line *line; 471: { 472: register int i; 473: register Line *top = windes->w_top; 474: 475: for (i = 0; top && i < windes->w_height - 1; i++, top = top->l_next) 476: if (top == line) 477: return FLine(windes) + i; 478: return -1; 479: } 480: 481: void 482: SplitWind() 483: { 484: SetWind(div_wind(curwind, is_an_arg() ? (arg_value() - 1) : 1)); 485: } 486: 487: /* Goto the window with the named buffer. If no such window 488: exists, pop one and attach the buffer to it. */ 489: void 490: GotoWind() 491: { 492: extern Buffer *lastbuf; 493: char *bname; 494: Window *w; 495: 496: bname = ask_buf(lastbuf); 497: w = curwind->w_next; 498: do { 499: if (w->w_bufp->b_name == bname) { 500: SetABuf(curbuf); 501: SetWind(w); 502: return; 503: } 504: w = w->w_next; 505: } while (w != curwind); 506: SetABuf(curbuf); 507: pop_wind(bname, NO, -1); 508: } 509: 510: void 511: ScrollRight() 512: { 513: int amt = (is_an_arg() ? arg_value() : 10); 514: 515: if (curwind->w_LRscroll - amt < 0) 516: curwind->w_LRscroll = 0; 517: else 518: curwind->w_LRscroll -= amt; 519: UpdModLine = YES; 520: } 521: 522: void 523: ScrollLeft() 524: { 525: int amt = (is_an_arg() ? arg_value() : 10); 526: 527: curwind->w_LRscroll += amt; 528: UpdModLine = YES; 529: }