home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / C++-7 / DISK4 / SAMPLES / CPPTUTOR / OOD / TEXTWIN.CP$ / TEXTWIN
Encoding:
Text File  |  1991-12-26  |  19.7 KB  |  684 lines

  1. /******************************************************************
  2.  
  3.  FILE: TEXTWIN.CPP
  4.  
  5. ******************************************************************/
  6.  
  7. #include "textwin.h"
  8.  
  9. #include <ctype.h>
  10.  
  11. /******************************************************************
  12.  
  13.  TextWin::TextWin
  14.  
  15.  This function creates a text window. It compares the size of the
  16.  text buffer with the size of the window, and allocates scrollbars
  17.  as needed.
  18.  
  19. ******************************************************************/
  20.  
  21. TextWin::TextWin( Point location, int wid, int len, Buffer *sheet )
  22. : Win(), canvas( *sheet )
  23. {
  24.     wid = min( wid, canvas.columns() + 2 );  // make sure window isn't
  25.     len = min( len, canvas.rows() + 2 );     //   larger than text buffer, or
  26.     wid = max( wid, TEXTWIN_MINWIDTH );      //   smaller than minimum
  27.     len = max( len, TEXTWIN_MINHEIGHT );
  28.  
  29.     area = Rect( location.x,
  30.                  location.y,
  31.                  location.x + wid - 1,
  32.                  location.y + len - 1 );
  33.  
  34.     textView = Rect( 1, 1, wid - 2, len - 2 );
  35.  
  36.     vscroller = hscroller = 0;
  37.  
  38.     if( canvas.rows() > textView.height() + 1 )
  39.     {
  40.         vscroller = new ScrollBar( this,
  41.                                    Point( textView.right + 1, textView.top ),
  42.                                    textView.height() + 1,
  43.                                    VERT );
  44.     }
  45.  
  46.     if( canvas.columns() > textView.width() + 1 )
  47.     {
  48.         hscroller = new ScrollBar( this,
  49.                                    Point( textView.left, textView.bottom + 1 ),
  50.                                    textView.width() + 1,
  51.                                    HORIZ );
  52.     }
  53.  
  54.     Interactor::activate();
  55.  
  56.     canvasOffset = Point( 0, 0 );
  57.     cursorPos = Point( 0, 0 );
  58. }
  59.  
  60. /******************************************************************
  61.  
  62.  TextWin::TextWin - copy constructor
  63.  
  64. ******************************************************************/
  65.  
  66. TextWin::TextWin( const TextWin& other )
  67. : canvas( other.canvas )
  68. {
  69.     if( other.hscroller )
  70.         hscroller = new ScrollBar( *other.hscroller );
  71.     if( other.vscroller )
  72.         vscroller = new ScrollBar( *other.vscroller );
  73.  
  74.     canvas = other.canvas;
  75.     textView = other.textView;
  76.     canvasOffset = other.canvasOffset;
  77.     cursorPos = other.cursorPos;
  78. }
  79.  
  80. /******************************************************************
  81.  
  82.  TextWin::operator=
  83.  
  84. ******************************************************************/
  85.  
  86. TextWin &TextWin::operator=( const TextWin& other )
  87. {
  88.     if( &other == this )   // check for self-assignment
  89.        return *this;
  90.  
  91.     if( hscroller )
  92.         delete hscroller;
  93.     if( vscroller )
  94.         delete vscroller;
  95.  
  96.     if( other.hscroller )
  97.         hscroller = new ScrollBar( *other.hscroller );
  98.     if( other.vscroller )
  99.         vscroller = new ScrollBar( *other.vscroller );
  100.  
  101.     canvas = other.canvas;
  102.     textView = other.textView;
  103.     canvasOffset = other.canvasOffset;
  104.     cursorPos = other.cursorPos;
  105.  
  106.     return *this;
  107. }
  108.  
  109. /******************************************************************
  110.  
  111.  TextWin::resize
  112.  
  113.  This function resizes the window to the specified dimensions.
  114.  If the specified dimensions fall below the minimum text window
  115.  size, or above the size of the text buffer, the specified
  116.  dimensions are adjusted accordingly. The function deletes or
  117.  creates scroll bars, as needed, and adjusts the position of
  118.  the window on the text buffer.
  119.  
  120. ******************************************************************/
  121.  
  122. void TextWin::resize( int newWidth, int newHeight )
  123. {
  124.     if( (newWidth == width())  &&
  125.         (newHeight == height())  )
  126.         return;                     // if same size, return
  127.  
  128.     newWidth = min( newWidth, canvas.columns() + 2 );  // ensure that window isn't
  129.     newWidth = max( newWidth, TEXTWIN_MINWIDTH );      //   larger than text buffer,
  130.     newHeight = min( newHeight, canvas.rows() + 2 );   //   or smaller than minimum
  131.     newHeight = max( newHeight, TEXTWIN_MINHEIGHT );
  132.  
  133.     textView = Rect( 1, 1, newWidth - 2, newHeight - 2 );
  134.  
  135.     Interactor::resize( newWidth, newHeight );
  136.  
  137.     if( canvas.rows() > textView.height() + 1 )  // Vertical scrollbar needed
  138.     {
  139.         if( vscroller )
  140.             delete vscroller;
  141.         vscroller = new ScrollBar( this,
  142.                                    Point( textView.right + 1, textView.top ),
  143.                                    textView.height() + 1,
  144.                                    VERT );
  145.         vscroller->setSlider( (canvasOffset.y * 100) / (canvas.rows() - (textView.height() + 1)) );
  146.     }
  147.     else if( vscroller )  // No vertical scrollbar needed
  148.     {
  149.         delete vscroller;
  150.         vscroller = 0;
  151.     }
  152.  
  153.     if( canvas.columns() > textView.width() + 1 ) // Horizontal scrollbar needed
  154.     {
  155.         if( hscroller )
  156.             delete hscroller;
  157.         hscroller = new ScrollBar( this,
  158.                                    Point( textView.left, textView.bottom + 1 ),
  159.                                    textView.width() + 1,
  160.                                    HORIZ );
  161.         hscroller->setSlider( (canvasOffset.x * 100) / (canvas.columns() - (textView.width() + 1)) );
  162.     }
  163.     else if( hscroller )  // No horizontal scrollbar needed
  164.     {
  165.         delete hscroller;
  166.         hscroller = 0;
  167.     }
  168.  
  169.     setCanvasOffset( getCanvasOffset() );  // Adjust canvas offset and cursor position
  170. }
  171.  
  172. /******************************************************************
  173.  
  174.  TextWin::activate
  175.  
  176.  This function activates the window and the scroll bars, if any
  177.  exist.
  178.  
  179. ******************************************************************/
  180.  
  181. void TextWin::activate()
  182. {
  183.     Interactor::activate();
  184.  
  185.     if( hscroller )
  186.         hscroller->activate();
  187.     if( vscroller )
  188.         vscroller->activate();
  189. }
  190.  
  191. /******************************************************************
  192.  
  193.  TextWin::deactivate
  194.  
  195.  This function deactivates the window and the scroll bars, if any
  196.  exist.
  197.  
  198. ******************************************************************/
  199.  
  200. void TextWin::deactivate()
  201. {
  202.     Interactor::deactivate();
  203.  
  204.     if( hscroller )
  205.         hscroller->deactivate();
  206.     if( vscroller )
  207.         vscroller->deactivate();
  208. }
  209.  
  210.  
  211. /******************************************************************
  212.  
  213.  TextWin::paint
  214.  
  215.  This function repaints the window, including text and scrollbars.
  216.  The painting region is set to the invalid rectangle for the
  217.  window's own painting. The invalid rectangle is passed on to the
  218.  scrollbars' paint functions, displaced to fit their coordinate
  219.  systems. Finally the painting region is reset to the entire
  220.  window, for the next time the window becomes active.
  221.  
  222. ******************************************************************/
  223.  
  224. void TextWin::paint( Rect invalid )
  225. {
  226.     paintingRegion = invalid;
  227.  
  228.     paintFrame();
  229.     if( vscroller )
  230.         vscroller->paint( invalid - vscroller->origin() );
  231.     if( hscroller )
  232.         hscroller->paint( invalid - hscroller->origin() );
  233.     paintText();
  234.  
  235.     paintingRegion = Rect( 0, 0, width(), height() );
  236. }
  237.  
  238. /******************************************************************
  239.  
  240.  TextWin::paintText
  241.  
  242.  This function repaints the text displayed in the window.
  243.  The mouse and text cursors are hidden, and the currently visible
  244.  text from the canvas is displayed.
  245.  
  246. ******************************************************************/
  247.  
  248. void TextWin::paintText() const
  249. {
  250.     int i,j;
  251.     MouseStatus mouseStat;
  252.  
  253.     ScreenChar temp;
  254.  
  255.     theMouse.read( &mouseStat );
  256.     if( withinBounds( mouseStat.position ) )
  257.         theMouse.hide();
  258.  
  259.     theScreen.cursorOff();
  260.  
  261.     for( i = 0; i < textView.width() + 1; i++ )
  262.     {
  263.         for( j = 0; j < textView.height() + 1; j++ )
  264.         {
  265.             temp = canvas.getChar( Point( i + canvasOffset.x,
  266.                                           j + canvasOffset.y) );
  267.             paintChar( Point( textView.left,
  268.                               textView.top ) + Point( i, j ),
  269.                        temp.character, temp.attribute );
  270.         }
  271.     }
  272.  
  273.     updateCursor();
  274.     theScreen.cursorOn();
  275.     if( withinBounds( mouseStat.position ) )
  276.         theMouse.show();
  277. }
  278.  
  279.  
  280. /******************************************************************
  281.  
  282.  TextWin::updateCursor
  283.  
  284.  This function moves the screen cursor to the location specified
  285.  by the cursorPos member variable.
  286.  
  287. ******************************************************************/
  288.  
  289. void TextWin::updateCursor() const
  290. {
  291.     theScreen.setCurPos( origin() +
  292.                          cursorPos +
  293.                          Point( textView.left, textView.top ) -
  294.                          canvasOffset );
  295. }
  296.  
  297.  
  298. /******************************************************************
  299.  
  300.  TextWin::updateScrollBars
  301.  
  302.  This function sets the scrollbar sliders, and repaints them.
  303.  
  304. ******************************************************************/
  305.  
  306. void TextWin::updateScrollBars()
  307. {
  308.     if( vscroller )
  309.     {
  310.         vscroller->setSlider( (canvasOffset.y * 100) /
  311.                               (canvas.rows() - (textView.height() + 1)) );
  312.         vscroller->paint( Rect( 0, 0,
  313.                                 vscroller->width(), vscroller->height() ) );
  314.     }
  315.     if( hscroller )
  316.     {
  317.         hscroller->setSlider( (canvasOffset.x * 100) /
  318.                               (canvas.columns() - (textView.width() + 1)) );
  319.         hscroller->paint( Rect( 0, 0,
  320.                                 hscroller->width(), hscroller->height() ) );
  321.     }
  322. }
  323.  
  324.  
  325. /********************************************************************
  326.  
  327.  TextWin::setCanvasOffset
  328.  
  329.  The canvas offset is the text buffer position of the first character
  330.  displayed text in the window.
  331.  
  332.  This function sets the canvas offset to the specified location.
  333.  If the cursor position no longer falls within the displayed
  334.  area of text (specified by the canvas offset and the dimensions of
  335.  the window), the cursor position is adjusted. This keeps the cursor
  336.  on screen when scrolling is performed with the scroll bars.
  337.  
  338. ********************************************************************/
  339.  
  340. void TextWin::setCanvasOffset( Point pos )
  341. {
  342.  
  343.     // ensure that text area doesn't fall outside text buffer
  344.     pos.y = max( pos.y, 0 );
  345.     pos.y = min( pos.y, canvas.rows() - (textView.height() + 1) );
  346.     pos.x = max( pos.x, 0 );
  347.     pos.x = min( pos.x, canvas.columns() - (textView.width() + 1) );
  348.  
  349.     canvasOffset = pos;
  350.  
  351.     // move cursor within displayed text area
  352.     cursorPos.y = max( pos.y, cursorPos.y );
  353.     cursorPos.y = min( pos.y + textView.height(), cursorPos.y );
  354.     cursorPos.x = max( pos.x, cursorPos.x );
  355.     cursorPos.x = min( pos.x + textView.width(), cursorPos.x );
  356. }
  357.  
  358.  
  359. /******************************************************************
  360.  
  361.  TextWin::setCursorPos
  362.  
  363.  This function sets the cursor to the specified location. If the
  364.  new cursor position doesn't fall within the currently displayed
  365.  area of text, the canvas offset is adjusted just enough so that
  366.  the cursor position is displayed. This allows cursor movement to
  367.  causes scrolling.
  368.  
  369.  returns: TRUE, if the text displayed has been shifted. Requires
  370.               that paintText() be called.
  371.           FALSE, if the text displayed has not been shifted.
  372.               Requires that updateCursor() be called.
  373.  
  374. ******************************************************************/
  375.  
  376. int TextWin::setCursorPos( Point loc )
  377. {
  378.     int shifted = FALSE;
  379.     Point newCanvasOffset = canvasOffset;
  380.  
  381.     // ensure that cursor is within text buffer
  382.     loc.y = max( loc.y, 0 );
  383.     loc.y = min( loc.y, canvas.rows() - 1 );
  384.     loc.x = max( loc.x, 0 );
  385.     loc.x = min( loc.x, canvas.columns() - 1 );
  386.  
  387.     cursorPos = loc;
  388.  
  389.     // check if cursor is outside displayed text area
  390.     if( cursorPos.y < canvasOffset.y )
  391.     {
  392.         newCanvasOffset.y = cursorPos.y;
  393.         shifted = TRUE;
  394.     }
  395.     else if( cursorPos.y > canvasOffset.y + textView.height() )
  396.     {
  397.         newCanvasOffset.y = cursorPos.y - textView.height();
  398.         shifted = TRUE;
  399.     }
  400.  
  401.     if( cursorPos.x < canvasOffset.x )
  402.     {
  403.         newCanvasOffset.x = cursorPos.x;
  404.         shifted = TRUE;
  405.     }
  406.     else if( cursorPos.x > canvasOffset.x + textView.width() )
  407.     {
  408.         newCanvasOffset.x = cursorPos.x - textView.width();
  409.         shifted = TRUE;
  410.     }
  411.  
  412.     if( shifted )  // adjust canvas offset so cursor is within bounds
  413.         canvasOffset = newCanvasOffset;
  414.  
  415.     return shifted;
  416. }
  417.  
  418.  
  419. /******************************************************************
  420.  
  421.  TextWin::handleEvent
  422.  
  423.  This function determines the type of event, and passes it on to
  424.  the appropriate event handler.
  425.  
  426. ******************************************************************/
  427.  
  428. void TextWin::handleEvent( const Event &action )
  429. {
  430.     switch ( action.getType() )
  431.     {
  432.     case KBD_EVENT:
  433.         handleKey( (KbdEvent &)action );
  434.         break;
  435.     case MOUSE_EVENT:
  436.         handleMouse( (MouseEvent &)action );
  437.         break;
  438.     case SCRL_EVENT:
  439.         handleScroll( (ScrollEvent &)action );
  440.         break;
  441.     default:
  442.         break;
  443.     };
  444. }
  445.  
  446.  
  447. /******************************************************************
  448.  
  449.  TextWin::handleKey
  450.  
  451.  This function handles keyboard events. The cursor movement keys
  452.  are handled, including the arrow keys, HOME, END, PGUP, and PGDN.
  453.  
  454. ******************************************************************/
  455.  
  456. void TextWin::handleKey( const KbdEvent &key )
  457. {
  458.     if( (key.val() == UPARROW) ||
  459.         (key.val() == DOWNARROW) ||
  460.         (key.val() == LEFTARROW) ||
  461.         (key.val() == RIGHTARROW) ||
  462.         (key.val() == HOME) ||
  463.         (key.val() == END) )
  464.     {
  465.         Point delta;    // a vector indicating cursor movement
  466.  
  467.         switch ( key.val() )
  468.         {
  469.         case UPARROW:
  470.             delta = Point( 0, -1 );
  471.             break;
  472.         case DOWNARROW:
  473.             delta = Point( 0, 1 );
  474.             break;
  475.         case LEFTARROW:
  476.             delta = Point( -1, 0 );
  477.             break;
  478.         case RIGHTARROW:
  479.             delta = Point( 1, 0 );
  480.             break;
  481.         case HOME:
  482.             delta = Point( -cursorPos.x, 0 );
  483.             break;
  484.         case END:
  485.             delta = Point( canvas.columns() - 1 - cursorPos.x, 0 );
  486.             break;
  487.         default:
  488.             break;
  489.         }
  490.  
  491.         if( setCursorPos( cursorPos + delta ) )
  492.         {
  493.             updateScrollBars();
  494.             paintText();
  495.         }
  496.         else
  497.             updateCursor();
  498.     }
  499.     else
  500.  
  501.         switch( key.val() )
  502.         {
  503.         case PGUP:
  504.            setCanvasOffset( canvasOffset + Point( 0, -textView.height() + 1 ) );
  505.            updateScrollBars();
  506.            paintText();
  507.            break;
  508.         case PGDN:
  509.            setCanvasOffset( canvasOffset + Point( 0, textView.height() - 1 ) );
  510.            updateScrollBars();
  511.            paintText();
  512.            break;
  513.         default:
  514.            break;
  515.         };
  516. }
  517.  
  518.  
  519. /******************************************************************
  520.  
  521.  TextWin::handleMouse
  522.  
  523.  This function handles mouse events. Mouse events that fall on
  524.  one of the scrollbars are passed to that object. The location of
  525.  the mouse event is translated to the scrollbar's coordinate system
  526.  when it is passed. Mouse events that fall on the text cause the
  527.  cursor position to be updated.
  528.  
  529. ******************************************************************/
  530.  
  531. void TextWin::handleMouse( const MouseEvent &action )
  532. {
  533.     if( vscroller &&
  534.         vscroller->withinBounds( action.getPosition() ) )
  535.     {
  536.         MouseEvent localAction( action.getPosition() - vscroller->origin(),
  537.                                 action.getButton() );
  538.         vscroller->handleEvent( localAction );
  539.     }
  540.     else if( hscroller &&
  541.              hscroller->withinBounds( action.getPosition() ) )
  542.     {
  543.         MouseEvent localAction( action.getPosition() - hscroller->origin(),
  544.                                 action.getButton() );
  545.         hscroller->handleEvent( localAction );
  546.     }
  547.     else if( textView.Contains( action.getPosition() ) )
  548.     {
  549.        setCursorPos( action.getPosition() -
  550.                      Point( textView.left, textView.top ) +
  551.                      canvasOffset );
  552.        updateCursor();
  553.     }
  554. }
  555.  
  556. /******************************************************************
  557.  
  558.  TextWin::handleScroll
  559.  
  560.  This function handles scrolling events. The magnitude and
  561.  direction of the event is examined, and the source of the
  562.  event is checked against the window's scrollbars. A vector
  563.  indicating the amount of text movement is defined, and the
  564.  cursor is moved accordingly.
  565.  
  566. ******************************************************************/
  567.  
  568. void TextWin::handleScroll( const ScrollEvent &action )
  569. {
  570.     int dir = action.getDirection(),
  571.         dist = action.getDistance();
  572.     ScrollBar *source = action.getSource();
  573.  
  574.     Point delta;  // a vector indicating text scrolling
  575.  
  576.     if( dir == FORWARD )
  577.     {
  578.         if( dist == LINE )
  579.             if( source == vscroller )
  580.                 delta = Point( 0, 1 );
  581.             else
  582.                 delta = Point( 1, 0 );
  583.  
  584.         else  // dist == PAGE
  585.             if( source == vscroller )
  586.                 delta = Point( 0, textView.height() - 1 );
  587.         else
  588.                 delta = Point( textView.width() - 1, 0 );
  589.     }
  590.     else  // dir == BACKWARD
  591.     {
  592.         if( dist == LINE )
  593.             if( source == vscroller )
  594.                 delta = Point( 0, -1 );
  595.             else
  596.                 delta = Point( -1, 0 );
  597.  
  598.         else  // dist == PAGE
  599.             if( source == vscroller )
  600.                 delta = Point( 0, -textView.height() + 1 );
  601.             else
  602.                 delta = Point( -textView.width() + 1, 0 );
  603.     }
  604.  
  605.     setCanvasOffset( canvasOffset + delta );
  606.  
  607.     updateScrollBars();
  608.     paintText();
  609.  
  610. }
  611.  
  612. /******************************************************************
  613.  
  614.  TextWin::~TextWin
  615.  
  616.  This function deletes the scroll bars, if any exist.
  617.  
  618. ******************************************************************/
  619.  
  620. TextWin::~TextWin()
  621. {
  622.     if( hscroller )
  623.         delete hscroller;
  624.     if( vscroller )
  625.         delete vscroller;
  626.  
  627. }
  628.  
  629.  
  630. /******************************************************************
  631.  
  632.  EditWin::handleEvent
  633.  
  634.  This function performs the event handling specific to editing
  635.  windows. If the received event is a keyboard event, and if it
  636.  is a printable character, the text buffer is modified and the
  637.  cursor position is updated. The backspace key is also handled.
  638.  All other events, keyboard or otherwise, are passed to TextWin's
  639.  handleEvent function.
  640.  
  641. ******************************************************************/
  642.  
  643. void EditWin::handleEvent( const Event &action )
  644. {
  645.     Point newCursorPos;
  646.  
  647.     switch ( action.getType() )
  648.     {
  649.     case KBD_EVENT:
  650.     {
  651.         KbdEvent &key = (KbdEvent &)action;
  652.  
  653.         if( isprint( (char)key.val() ) )
  654.         {
  655.             canvas.setChar( getCursorPos(), key.val() );
  656.  
  657.             newCursorPos = getCursorPos();
  658.             newCursorPos.x++;
  659.  
  660.             if( newCursorPos.x == canvas.columns() )
  661.             {
  662.                 newCursorPos.x = 0;
  663.                 newCursorPos.y++;
  664.             }
  665.             if( newCursorPos.y == canvas.rows() )
  666.                 newCursorPos = Point( canvas.columns() - 1,
  667.                                       canvas.rows() - 1 );
  668.  
  669.             if( setCursorPos( newCursorPos ) )   // setCursorPos handles scrolling
  670.                 updateScrollBars();
  671.  
  672.             paintText();
  673.         }
  674.         else
  675.             TextWin::handleEvent( action );
  676.  
  677.         break;
  678.     }
  679.     default:
  680.         TextWin::handleEvent( action );
  681.         break;
  682.     };
  683. }
  684.