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 variables pertaining to scrolling the text - as shown below.

struct window_data
{
    int width_of_character,
        height_of_character,
        width_of_capitals,
        position_of_vertical_scroll,
        height_of_client;

    window_data()
    {
        position_of_vertical_scroll = 0;
    }
};

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

height_of_client The current height of the client area.
position_of_vertical_scroll The current position of the vertical scroll bar.

The processing for message::vertical_scroll is shown below.

case message::vertical_scroll:
 switch(low_part(parameter1))
  {
   case scrollbar_notify::line_up:
    position_of_vertical_scroll -= 1;
    break;

   case scrollbar_notify::line_down:
    position_of_vertical_scroll += 1;
    break;

   case scrollbar_notify::page_up:
    position_of_vertical_scroll -= height_of_client / height_of_character;
    break;

   case scrollbar_notify::page_down:
    position_of_vertical_scroll += height_of_client / height_of_character;
    break;

   case scrollbar_notify::slider_position:
    position_of_vertical_scroll = high_part(parameter1);
    break;
  }

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

 if (position_of_vertical_scroll != get_scroll_position(window_handle,scrollbar_identity::Vertical))
  {
   set_scroll_position(window_handle,scrollbar_identity::Vertical,position_of_vertical_scroll,true);
   invalidate_rectangle(window_handle,(const rectangle*)null,true);
  }
 break;

The expression low_part(parameter1) yields the scroll bar notification code. For notifications scrollbar_notify::line_up and scrollbar_notify::line_down, the position of the scroll is decremented or incremented (respectively) by a single unit. For notifications scrollbar_notify::page_up and scrollbar_notify::page_down, the position is decremented or incremented (respectively) by the number of lines that fit the current size of the client window. The notification scrollbar_notify::slider_position is sent when scrolling is being ended and the expression high_part(parameter1) is used to calculate the new position. after one of these calculations has been performed, the statement:

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

is used to adjust the variable position_of_vertical_scroll 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 (position_of_vertical_scroll != get_scroll_position(window_handle,scrollbar_identity::Vertical))

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

if (position_of_vertical_scroll != get_scroll_position(window_handle,scrollbar_identity::Vertical))
 {
  set_scroll_position(window_handle,scrollbar_identity::Vertical,position_of_vertical_scroll,true);
  invalidate_rectangle(window_handle,(const rectangle*)null,true);
 }

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

   case message::paint:
    {
     paint paint_structure;
     handle device_context = begin_paint(window,&paint_structure);

     enum {Column1=30, Column2=40};

     for (int i=0; i<lines; i++)
      {
       text_out(device_context,
               width_of_character,
               height_of_character * (i+1),
               Metrics[i].title,
               string_length(Metrics[i].title));

       text_out(device_context,
               width_of_character + Column1 * width_of_capitals,
               height_of_character * (i+1),
               Metrics[i].Description,
               string_length(Metrics[i].Description));

       set_text_alignment(device_context,text_alignment_flag::right | text_alignment_flag::top);

       character Buffer[32];

       text_out(device_context,
               width_of_character + Column1 * width_of_capitals + Column2 * width_of_character,
               height_of_character * (i+1),
               Buffer,
               print_string(Buffer, "%5d",get_system_metrics(Metrics[i].Index)));

       set_text_alignment(device_context,text_alignment_flag::left | text_alignment_flag::top);
     }

     end_paint(window,&paint_structure);
    }
    break;

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

int y = height_of_character * (1 - position_of_vertical_scroll + i);

yields the line at which drawing commences.