Vertically Scrolling Text


This program builds upon the previous program and adds the feature of vertical scrolling of the text. The output of the program is shown below (see also the full code listing).

Whilst not all text is visible, a vertical scroll bar has been added to facilitate scrolling lines of text into view. The window procedure contains several additional static variables pertaining to scrolling the text - as shown below.

void* __stdcall Client(void* window,
                       unsigned Identity,
                       void* parameter1,
                       void* parameter2)
{
 Handle Window(window);
 Handle Parameter1(parameter1);
 Handle Parameter2(parameter2);

 static int WidthOfCharacter,
            HeightOfCharacter,
            WidthOfCapitals,
            PositionOfVerticalScroll,
            HeightOfClient;
... 

The variables that have been added are shown in the table below.

HeightOfClient The current height of the client area.
PositionOfVerticalScroll The current position of the vertical scroll bar.

The processing for Message::VerticalScroll is shown below.

case Message::VerticalScroll:
 switch(Parameter1.LowPart)
  {
   case ScrollbarNotify::LineUp:
    PositionOfVerticalScroll -= 1;
    break;

   case ScrollbarNotify::LineDown:
    PositionOfVerticalScroll += 1;
    break;

   case ScrollbarNotify::PageUp:
    PositionOfVerticalScroll -= HeightOfClient / HeightOfCharacter;
    break;

   case ScrollbarNotify::PageDown:
    PositionOfVerticalScroll += HeightOfClient / HeightOfCharacter;
    break;

   case ScrollbarNotify::SliderPosition:
    PositionOfVerticalScroll = Parameter1.HighPart;
    break;
  }

 PositionOfVerticalScroll = maximum(0,minimum(PositionOfVerticalScroll,(int)lines));

 if (PositionOfVerticalScroll != Win::GetScrollPosition(WindowHandle,ScrollbarIdentity::Vertical))
  {
   Win::SetScrollPosition(WindowHandle,ScrollbarIdentity::Vertical,PositionOfVerticalScroll,true);
   Win::InvalidateRectangle(WindowHandle,(const Rectangle*)Null,true);
  }
 break;

The expression Parameter1.LowPart yields the scroll bar notification code. For notifications ScrollbarNotify::LineUp and ScrollbarNotify::LineDown, the position of the scroll is decremented or incremented (respectively) by a single unit. For notifications ScrollbarNotify::PageUp and ScrollbarNotify::PageDown, the position is decremented or incremented (respectively) by the number of lines that fit the current size of the client window. The notification ScrollbarNotify::SliderPosition is sent when scrolling is being ended and the expression Parameter1.HighPart is used to calculate the new position. After one of these calculations has been performed, the statement:

PositionOfVerticalScroll = maximum(0,minimum(PositionOfVerticalScroll,(int)Lines));

is used to adjust the variable PositionOfVerticalScroll to fit the boundaries (in case it is negative or greater than the scrolling range). Next, the current position of the scroll bar is queried through the statement

if (PositionOfVerticalScroll != Win::GetScrollPosition(WindowHandle,ScrollbarIdentity::Vertical))

If the position has changed, the new scroll bar position is set through the code sequence shown below.

if (PositionOfVerticalScroll != Win::GetScrollPosition(WindowHandle,ScrollbarIdentity::Vertical))
 {
  Win::SetScrollPosition(WindowHandle,ScrollbarIdentity::Vertical,PositionOfVerticalScroll,true);
  Win::InvalidateRectangle(WindowHandle,(const Rectangle*)Null,true);
 }

The paint routine has also changed and it is shown below.

   case (unsigned)Message::Paint:
    {
     Paint^ PaintStruct = gcnew Paint();

     Handle DeviceContext = Gdi::BeginPaint(Window,PaintStruct);

     enum {Column1=30, Column2=40};

     for (int i=0; i<Lines; i++)
      {
       int y = HeightOfCharacter * (1 - PositionOfVerticalScroll + i);

       Gdi::TextOut(DeviceContext,
                    WidthOfCharacter,
                    y,
                    gcnew String(Metrics[i].Title));

       Gdi::TextOut(DeviceContext,
                    WidthOfCharacter + Column1 * WidthOfCapitals,
                    y,
                    gcnew String(Metrics[i].Description));

       Gdi::SetTextAlignment(DeviceContext,(int)TextAlignment::Right | (int)TextAlignment::Top);

       Gdi::TextOut(DeviceContext,
                    WidthOfCharacter + Column1 * WidthOfCapitals + Column2 * WidthOfCharacter,
                    y,
                    Win::GetSystemMetrics(Metrics[i].Index).ToString());

       Gdi::SetTextAlignment(DeviceContext,(int)TextAlignment::Left | (int)TextAlignment::Top);
     }

     Gdi::EndPaint(Window,PaintStruct);
    }
    break;

The y-coordinate is calculated by factoring the current position of the scroll bar into the drawing. The statement

int y = HeightOfCharacter * (1 - PositionOfVerticalScroll + i);

yields the line at which drawing commences.