home *** CD-ROM | disk | FTP | other *** search
/ Mac Expert 1995 Winter / Mac Expert - Winter 95.iso / Les fichiers / Communications / Internet / TurboTCP 2.1 ƒ / PP MiniTelnet source / CTerminalPane.cp < prev    next >
Encoding:
Text File  |  1995-01-19  |  16.0 KB  |  763 lines  |  [TEXT/MMCC]

  1. //
  2. // CTerminalPane.cp
  3. //
  4. //    TerminalPane library
  5. //    Terminal display pane
  6. //    PowerPlant version
  7. //
  8. //    Copyright © 1993–95, FrostByte Design / Eric Scouten
  9. //
  10.  
  11. #include "CTerminalPane.h"
  12.  
  13. #include <Events.h>
  14.  
  15.  
  16. #define resetInvalsChar 3
  17.  
  18.  
  19. //    —— constructor ——
  20.  
  21. //***********************************************************
  22.  
  23. /*______________________________________________________________________
  24. **
  25. ** constructors
  26. **
  27. **    Initialize the pane. Nothing special here. Parameters and usage are all the same
  28. **    as for CPanorama.
  29. **
  30. */
  31.  
  32.  
  33.  
  34.  
  35.  
  36. //***********************************************************
  37.  
  38.  
  39.  
  40.  
  41. //***********************************************************
  42.  
  43. /*______________________________________________________________________
  44. **
  45. ** CTerminalPaneX (private method)
  46. **
  47. **    Finish initialization for terminal pane.
  48. **
  49. */
  50.  
  51.  
  52.  
  53.  
  54. //    —— drawing  ——
  55.  
  56. //***********************************************************
  57.  
  58. /*______________________________________________________________________
  59. **
  60. ** Draw
  61. **
  62. **    Draw characters from the theScreen array onto the real screen.
  63. **
  64. **        area (Rect*):    area to be redrawn (in frame coordinates)
  65. **
  66. */
  67.  
  68.  
  69.  
  70.  
  71. //    —— blinking cursor support ——
  72.  
  73. //***********************************************************
  74.  
  75. /*______________________________________________________________________
  76. **
  77. ** Dawdle
  78. **
  79. **    Blink the cursor if necessary. Cursor blinks at the user-defined rate for insertion point
  80. **    blinking.
  81. **
  82. **        maxSleep (long*):    maximum sleep value, updated if necessary
  83. **
  84. */
  85.  
  86.  
  87.  
  88. //***********************************************************
  89.  
  90. /*______________________________________________________________________
  91. **
  92. ** BecomeGopher
  93. **
  94. **    Become the gopher (or leave gopher status). All our routine does is force a refresh
  95. **    of the cursor.
  96. **
  97. **        fBecoming (Boolean):        TRUE if becoming gopher
  98. **
  99. **        return (Boolean):        TRUE if successful in changing status
  100. **
  101. */
  102.  
  103.  
  104.  
  105. //***********************************************************
  106.  
  107. /*______________________________________________________________________
  108. **
  109. ** SetBlinking
  110. **
  111. **    Turns on or off cursor blinking.
  112. **
  113. **        blinkMode (Boolean):        TRUE to enable cursor blinking
  114. **
  115. */
  116.  
  117. void CTerminalPane::SetBlinking(Boolean blinkMode)
  118.  
  119. {
  120.     blinkCursor = blinkMode;
  121.     if ((blinkMode)    && (IsActive())) {
  122.         lastCursorCol = theColumn;
  123.         lastCursorLine = theLine;
  124.         CursorMoved();
  125.     }
  126.     else {
  127.         cursorVis = true;
  128.         InvalCharRect(theColumn, theLine, theColumn, theLine);
  129.     }
  130. }
  131.  
  132.  
  133. //    —— scrolling ——
  134.  
  135. //***********************************************************
  136.  
  137. /*______________________________________________________________________
  138. **
  139. ** ScrollToSelection
  140. **
  141. **    Ensure that the current cursor location is visible.
  142. **
  143. */
  144.  
  145. void CTerminalPane::ScrollToSelection()
  146.  
  147. {
  148. /* //! TEMPORARY: ignore for now…
  149.     short    hSpan, vSpan;
  150.     LongRect    topLeftRect, botRightRect;            // top left / bottom right cells of selection
  151.                                             // held over from CTable::ScrollToSelection
  152.                                             // because we might implement character selection later
  153.     LongPt    selPos;
  154.  
  155.  
  156.     // get current window parameters
  157.  
  158.     if (EmptyLongRect(&aperture))                    // nothing selected or nothing visible
  159.         return;
  160.     GetFrameSpan(&hSpan, &vSpan);
  161.     selPos = position;                            // init to current scroll position
  162.  
  163.  
  164.     // figure out where cursor (or selection) is
  165.  
  166.     CalcCharRect(theColumn, theLine, theColumn, theLine, &topLeftRect);
  167.     topLeftRect.left -= offsetX;
  168.     topLeftRect.top -= offsetY;
  169.     topLeftRect.right += offsetX;
  170.     topLeftRect.bottom += offsetY;
  171.     botRightRect = topLeftRect;
  172.             // adapt later for charcter selections
  173.  
  174.  
  175.     // calc vertical scroll
  176.  
  177.     if (topLeftRect.bottom >= position.v + vSpan)        // Is the top of selection below the bottom of frame?
  178.         selPos.v = topLeftRect.bottom - vSpan;
  179.     else if (botRightRect.top < position.v)            // Is the bottom of selection above the top of the frame?
  180.         selPos.v = botRightRect.top;
  181.  
  182.  
  183.     // calc horizontal scroll
  184.  
  185.     if (topLeftRect.right >= position.h + hSpan)        // Is the left edge of selection past the right edge of frame?
  186.         selPos.h = topLeftRect.right - hSpan;
  187.     else if (botRightRect.left < position.h)            // Is the right edge of selection before the left edge of frame?
  188.         selPos.h = botRightRect.left;
  189.  
  190.     if ((selPos.h != position.h) || (selPos.v != position.v))
  191.         ScrollTo(&selPos, TRUE);
  192. */
  193. }
  194.  
  195.  
  196. //***********************************************************
  197.  
  198. /*______________________________________________________________________
  199. **
  200. ** DisableKeyScroll
  201. **
  202. **    Turn on or off keyboard scrolling commands.
  203. **
  204. **        disable (Boolean):    TRUE to turn off keyboard scrolling
  205. **
  206. */
  207.  
  208. void CTerminalPane::DisableKeyScroll(Boolean disable)
  209.  
  210. {
  211.     disableKeyScroll = disable;
  212. }
  213.  
  214. //***********************************************************
  215.  
  216.  
  217. /*______________________________________________________________________
  218. **
  219. ** DoKeyDown
  220. **
  221. **    Override to enable or disable key scrolling (which is implemented in CPanorama).
  222. **
  223. */
  224.  
  225.  
  226.  
  227.  
  228. //    —— terminal emulation methods ——
  229.  
  230. //***********************************************************
  231.  
  232. /*______________________________________________________________________
  233. **
  234. ** DoClearScreen
  235. **
  236. **    Clear the screen and move the cursor to (0,0).
  237. **
  238. */
  239.  
  240. void CTerminalPane::DoClearScreen()
  241.  
  242. {
  243.     register short x, y;
  244.     
  245.     theLine = theColumn = 0;
  246.     CursorMoved();
  247.  
  248.     for (y = 0; y < maxY; ++y)
  249.         for (x = 0; x < maxX; ++x)
  250.             theScreen[y][x] = ' ';
  251.     Refresh();
  252. }
  253.  
  254.  
  255. //***********************************************************
  256.  
  257. /*______________________________________________________________________
  258. **
  259. ** DoWriteChar
  260. **
  261. **    Write a character to the terminal. This method handles *basic* terminal emulation.
  262. **    To provide more sophisticated emulation, override this method.
  263. **
  264. **        theChar (char):        the character to write
  265. **
  266. */
  267.  
  268. void CTerminalPane::DoWriteChar(char theChar)
  269.  
  270. {
  271.  
  272.     // parse a few control characters
  273.  
  274.     switch (theChar) {
  275.  
  276.         case charNUL:
  277.             break;
  278.  
  279.         case charBEL:
  280.             SysBeep(0);
  281.             break;
  282.  
  283.         case charBS:
  284.             if (theColumn > 0)
  285.                 theColumn--;
  286.             CursorMoved();
  287.             break;
  288.  
  289.         case charHT:
  290.             theColumn = ((short) ((theColumn + 7) / 8)) * 8;
  291.             if (theColumn >= maxX)
  292.                 theColumn = maxX-1;
  293.             CursorMoved();
  294.             break;
  295.             
  296.         case charLF:
  297.             if (theLine < maxY-1)
  298.                 theLine++;
  299.             else
  300.                 ScrollTerm();
  301.             CursorMoved();
  302.             ScrollToSelection();
  303.             break;
  304.             
  305.         case charFF:
  306.             DoClearScreen();
  307.             ScrollToSelection();
  308.             break;
  309.             
  310.         case charCR:
  311.             theColumn = 0;
  312.             CursorMoved();
  313.             break;
  314.         
  315.         default:
  316.             theScreen[theLine][theColumn] = theChar;
  317.             InvalCharRect(theColumn, theLine, theColumn, theLine);
  318.             if (theColumn < maxX-1)
  319.                 theColumn++;
  320.             CursorMoved();
  321.     }
  322. }
  323.  
  324. //***********************************************************
  325.  
  326. /*______________________________________________________________________
  327. **
  328. ** DoWriteStr
  329. **
  330. **    Write a string to the terminal. This method is optimized to handle text strings. It skips
  331. **    any control characters and sends them directly to DoWriteChar.
  332. **
  333. **        theStr (char*):        the string to write (C string)
  334. **
  335. */
  336.  
  337. void CTerminalPane::DoWriteStr(char* theStr)
  338.  
  339. {
  340.     short leftCol;
  341.  
  342.     // optimize for text characters
  343.     
  344.     while (*theStr) {
  345.         if (*theStr >= ' ') {
  346.             leftCol = theColumn;
  347.             while (*theStr >= ' ') {
  348.                 theScreen[theLine][theColumn] = *(theStr++);
  349.                 if (theColumn < maxX-1)
  350.                     theColumn++;
  351.             }
  352.             InvalCharRect(leftCol, theLine, theColumn, theLine);
  353.             CursorMoved();
  354.         }
  355.         if (*theStr)
  356.             DoWriteChar(*(theStr++));
  357.     }
  358. }
  359.  
  360.  
  361. //***********************************************************
  362.  
  363. /*______________________________________________________________________
  364. **
  365. ** DoWriteBfr
  366. **
  367. **    Write the contents of a text buffer to the terminal. This method
  368. **    merely dishes out the characters to the DoWriteChar method.
  369. **
  370. **        theStr (char*):        the buffer to write
  371. **        theSize (short):    size of the data buffer
  372. **
  373. */
  374.  
  375. void CTerminalPane::DoWriteBfr(char* theStr, short theSize)
  376.  
  377. {
  378.     while (theSize--)
  379.         DoWriteChar(*(theStr++));
  380. }
  381.  
  382.  
  383. //***********************************************************
  384.  
  385. /*______________________________________________________________________
  386. **
  387. ** DoWriteCharNum
  388. **
  389. **    Write a character number to the terminal. Provided as a debugging routine
  390. **    by other classes. The number is bracketed by the two characters indicated, i.e.
  391. **    if you call ::DoWriteCharNum('!', '[', ']'), you get [33] written to the terminal.
  392. **
  393. **        theChar (char):        the character number to write
  394. **        leftBracket (char):    prefix to character number
  395. **        rightBracket (char):    suffix to character number
  396. **
  397. */
  398.  
  399. void CTerminalPane::DoWriteCharNum(char theChar, char leftBracket, char rightBracket)
  400.  
  401. {
  402.     Str255 cNumber;
  403.  
  404.     if (leftBracket)
  405.         DoWriteChar(leftBracket);
  406.  
  407.     ::NumToString((short) theChar, cNumber);
  408.     cNumber[cNumber[0]+1] = '\0';
  409.     DoWriteStr((char*) (&cNumber)+1);
  410.  
  411.     if (rightBracket)    
  412.         DoWriteChar(rightBracket);
  413. }
  414.  
  415.  
  416. //***********************************************************
  417.  
  418. /*______________________________________________________________________
  419. **
  420. ** DoEraseChar
  421. **
  422. **    Erase one character from screen (backspace).
  423. **
  424. */
  425.  
  426. void CTerminalPane::DoEraseChar()
  427.  
  428. {
  429.     register short x;
  430.     
  431.     if (theColumn > 0) {
  432.         theColumn--;
  433.         for (x = theColumn; x < maxX-1; x++)
  434.             theScreen[theLine][x] = theScreen[theLine][x+1];
  435.         theScreen[theLine][maxX-1] = ' ';
  436.         InvalCharRect(theColumn, theLine, maxX-1, theLine);
  437.         CursorMoved();
  438.     }
  439. }
  440.  
  441.  
  442. //***********************************************************
  443.  
  444. /*______________________________________________________________________
  445. **
  446. ** DoEraseLine
  447. **
  448. **    Move the cursor back to beginning of line & erase line.
  449. **
  450. */
  451.  
  452. void CTerminalPane::DoEraseLine()
  453.  
  454. {
  455.     theColumn = 0;
  456.     ClearToEOL(0, theLine);
  457.     CursorMoved();
  458. }
  459.  
  460.  
  461. //    —— private screen handling methods ——
  462.  
  463. //***********************************************************
  464.  
  465. /*______________________________________________________________________
  466. **
  467. ** ClearToEOL (protected method)
  468. **
  469. **    Clear from the indicated point to the end of a line. Upper left
  470. **    corner is (0,0).
  471. **
  472. **        col (short):    first column in line to clear
  473. **        line (short):    line to be cleared
  474. **
  475. */
  476.  
  477. void CTerminalPane::ClearToEOL(short col, short line)
  478.  
  479. {
  480.     InvalCharRect(col, line, maxX-1, line);
  481.     while (col < maxX)
  482.         theScreen[line][col++] = ' ';
  483. }
  484.  
  485. //***********************************************************
  486.  
  487. /*______________________________________________________________________
  488. **
  489. ** ClearToEOS (protected method)
  490. **
  491. **    Clear from the indicated point to the end of the screen. Upper left
  492. **    corner is (0,0).
  493. **
  494. **        col (short):    first column in first line to clear
  495. **        line (short):    first line to be cleared
  496. **
  497. */
  498.  
  499. void CTerminalPane::ClearToEOS(short col, short line)
  500.  
  501. {
  502.     while (line < maxY) {
  503.         ClearToEOL(col, line++);
  504.         col = 0;
  505.     }
  506. }
  507.  
  508. //***********************************************************
  509.  
  510. /*______________________________________________________________________
  511. **
  512. ** ScrollTerm
  513. **
  514. **    Push everything on screen up one line.
  515. **
  516. */
  517.  
  518. void CTerminalPane::ScrollTerm()
  519.  
  520. {
  521.     ::BlockMoveData(&theScreen[1][0], &theScreen[0][0], (maxY-1) * maxX);
  522.     ClearToEOL(0, maxY-1);
  523.     Refresh();
  524. }
  525.  
  526.  
  527. //***********************************************************
  528.  
  529. /*______________________________________________________________________
  530. **
  531. ** InvalCharRect (protected method)
  532. **
  533. **    Invalidate a section of the pane based on the character coordinates
  534. **    provided. Upper left corner is (0,0).
  535. **
  536. **        left (short):        left edge of character rectangle
  537. **        top (short):        top edge
  538. **        right (short):        right edge, inclusive
  539. **        bottom (short):        bottom edge, inclusive
  540. **
  541. */
  542.  
  543. void CTerminalPane::InvalCharRect(short left, short top, short right, short bottom)
  544.  
  545. {
  546. //    LongRect    theLongRect;
  547.     Rect theRect;
  548.  
  549.     CalcCharRect(left, top, right, bottom, theRect);
  550.     FocusDraw();
  551.     InvalPortRect(&theRect);
  552.  
  553. }
  554.  
  555.  
  556. //***********************************************************
  557.  
  558. /*______________________________________________________________________
  559. **
  560. ** CursorMoved
  561. **
  562. **    Update the blinking cursor block.
  563. **
  564. */
  565.  
  566. void CTerminalPane::CursorMoved()
  567.  
  568. {
  569.     cursorVis = true;
  570.     lastCursorTick = LMGetTicks();
  571.     if (lastCursorLine == theLine) {
  572.         switch (charsToInvalLine) {
  573.             case 0:                            // optimization to reduce calls to InvalRect()
  574.                 break;
  575.             case 1:
  576.                 InvalCharRect(0, theLine, maxX-1, theLine);
  577.                 charsToInvalLine = 0;
  578.                 break;
  579.             default:
  580.                 InvalCharRect(lastCursorCol, lastCursorLine, lastCursorCol, lastCursorLine);
  581.                 InvalCharRect(theColumn, theLine, theColumn, theLine);
  582.                 charsToInvalLine--;
  583.         }
  584.     }
  585.     else {
  586.         InvalCharRect(lastCursorCol, lastCursorLine, lastCursorCol, lastCursorLine);
  587.         InvalCharRect(theColumn, theLine, theColumn, theLine);
  588.         charsToInvalLine = resetInvalsChar;
  589.     }
  590.     lastCursorCol = theColumn;
  591.     lastCursorLine = theLine;
  592. }
  593.  
  594. //***********************************************************
  595.  
  596.  
  597. /*______________________________________________________________________
  598. **
  599. ** CalcCharRect (protected method)
  600. **
  601. **    Calculate the screen coordinates for a specified rectangle of
  602. **    character coordinates. Upper left corner is (0,0).
  603. **
  604. **        left (short):            left edge of char rectangle
  605. **        top (short):            top edge
  606. **        right (short):            right edge, inclusize
  607. **        bottom (short):            bottom edge, inclusive
  608. **        theRect (LongRect*):    coordinates returned to this rectangle
  609. **
  610. */
  611.  
  612.  
  613.  
  614.  
  615. //***********************************************************
  616.  
  617. /*______________________________________________________________________
  618. **
  619. ** InvertCursor
  620. **
  621. **    Invert a single character.
  622. **
  623. **        col (short):    the column number
  624. **        line (short):    the line number
  625. **
  626. */
  627.  
  628. void CTerminalPane::InvertCursor(short col, short line)
  629.  
  630. {
  631. //    LongRect    theLongRect;
  632.     Rect        theRect;
  633.     
  634.     CalcCharRect(col, line, col, line, theRect);
  635. //    LongToQDRect(&theLongRect, &theRect);
  636.     ::InvertRect(&theRect);
  637.     if (!IsActive()) {
  638.         ::InsetRect(&theRect, 1, 1);
  639.         ::InvertRect(&theRect);
  640.     }
  641. }
  642.  
  643. void CTerminalPane::Activate()
  644. {
  645.     cursorVis = true;
  646.     InvalCharRect(theColumn, theLine, theColumn, theLine);
  647. }
  648.  
  649.  
  650. void    CTerminalPane::CalcCharRect(short left, short top, short right, short bottom, Rect& theRect)
  651.  
  652. {
  653.     theRect.left = left * pixelsX + offsetX;
  654.     theRect.top = top * pixelsY + offsetY;
  655.     theRect.right = (right+1) * pixelsX + offsetX;
  656.     theRect.bottom = (bottom+1) * pixelsY + offsetY;
  657. }
  658.  
  659.  
  660. void CTerminalPane::SpendTime(const EventRecord& inMacEvent)
  661.  
  662. {
  663.     if (!IsActive())
  664.         return;
  665.         
  666.     if (blinkCursor) {
  667.         if (LMGetTicks() >= lastCursorTick + GetCaretTime()) {
  668.             cursorVis = !cursorVis;
  669.             lastCursorTick = LMGetTicks();
  670.             InvalCharRect(theColumn, theLine, theColumn, theLine);
  671.         }
  672.     }
  673. }
  674.  
  675.  
  676. void    CTerminalPane::DrawSelf()
  677. {
  678.     short    left, top, right, bottom;        // char coordinatates of draw region
  679.     short    dLine;                    // where to draw now
  680. //    LongRect    theLongArea;                // frame coordinates of region
  681. //    LongPt    theLongPt;
  682. //    Point        thePoint;
  683.  
  684. /*    TEMPORARY: for now, just draw the whole thing every time…
  685.     // figure draw region
  686.  
  687.     charsToInvalLine = resetInvalsChar;
  688.     QDToFrameR(area, &theLongArea);
  689.     left = (theLongArea.left - offsetX) / pixelsX;
  690.     right = (theLongArea.right -offsetX + 1) / pixelsX;
  691.     top = (theLongArea.top - offsetY) / pixelsY;
  692.     bottom = (theLongArea.bottom -offsetY + 1) / pixelsY;
  693.  
  694.     // do range checking
  695.  
  696.     left = TCLMax(left, 0);
  697.     top = TCLMax(top, 0);
  698.     right = TCLMin(right, maxX-1);
  699.     bottom = TCLMin(bottom, maxY-1);
  700. */
  701. left = top = 0;
  702. right = maxX - 1;
  703. bottom = maxY - 1;
  704.  
  705.     // hard-wire for Monaco 9: Mom, don’t look at this code!
  706.  
  707.     ::TextFont(4);
  708.     ::TextFace(0);
  709.     ::TextSize(9);
  710.  
  711.  
  712.     // draw the stuff
  713.  
  714.     if (left <= right) {
  715.         dLine = top;
  716.         while (dLine <= bottom) {
  717. //            SetLongPt(&theLongPt, left * pixelsX, dLine * pixelsY);
  718. //            FrameToQD(&theLongPt, &thePoint);
  719.             ::MoveTo(left * pixelsX + offsetX, dLine * pixelsY + offsetY + pixelsY-2);
  720.             ::DrawText(&theScreen[dLine][left], 0, right-left+1);
  721.             dLine++;
  722.         }
  723.     }
  724.  
  725.  
  726.     // check to see if we overwrote the cursor
  727.  
  728.     if ((left <= theColumn) && (right >= theColumn) &&
  729.      (top <= theLine) && (bottom >= theLine) && cursorVis)
  730.          InvertCursor(theColumn, theLine);
  731.     
  732. }
  733.  
  734.  
  735. void CTerminalPane::Deactivate()
  736. {
  737.     cursorVis = true;
  738.     InvalCharRect(theColumn, theLine, theColumn, theLine);
  739. }
  740.  
  741.  
  742. CTerminalPane::CTerminalPane(LStream* inStream)
  743.  
  744. : LView(inStream)
  745. {
  746. //    LongRect theBounds;
  747.  
  748.     charsToInvalLine = resetInvalsChar;
  749.     blinkCursor = false;
  750.     cursorVis = true;
  751.     lastCursorCol = lastCursorLine = 0;
  752.     lastCursorTick = 0L;
  753.     disableKeyScroll = false;
  754.     DoClearScreen();
  755. }
  756.  
  757.  
  758. CTerminalPane* CTerminalPane::CreateTerminalPaneStream(LStream* inStream)
  759. {
  760.     return new CTerminalPane(inStream);
  761. }
  762.  
  763.