+void Display_SetScrollArea(tTerminal *Term, int Start, int Count)
+{
+ assert(Start >= 0);
+ assert(Count >= 0);
+ Term->ScrollTop = Start;
+ Term->ScrollRows = MIN(Count, Term->ViewRows - Start);
+}
+
+void Display_ScrollDown(tTerminal *Term, int Count)
+{
+ int top, max;
+ tLine *buffer;
+
+ if( Term->bUsingAltBuf )
+ {
+ top = (Term->ScrollRows == 0 ? 0 : Term->ScrollTop);
+ max = (Term->ScrollRows == 0 ? Term->ViewRows : Term->ScrollRows);
+ buffer = Term->AltBuf;
+ }
+ else
+ {
+ top = 0;
+ max = Term->TotalLines;
+ buffer = Term->PriBuf;
+ }
+
+ assert(Count < max);
+ assert(Count > -max);
+
+ DEBUGS("Scroll %p %i-%i down by %i", buffer, top, max, Count);
+
+ buffer += top;
+
+ int clear_top, clear_max;
+ if( Count < 0 )
+ {
+ // -ve: Scroll up, move buffer contents down
+ Count = -Count;
+ for( int i = max-Count; i < max; i ++ )
+ free(buffer[i].Data);
+ memmove(buffer+Count, buffer, (max-Count)*sizeof(*buffer));
+
+ clear_top = 0;
+ clear_max = Count;
+ }
+ else
+ {
+ for( int i = 0; i < Count; i ++ )
+ free(buffer[i].Data);
+ memmove(buffer, buffer+Count, (max-Count)*sizeof(*buffer));
+ clear_top = max-Count;
+ clear_max = max;
+ }
+ // Clear exposed lines
+ for( int i = clear_top; i < clear_max; i ++ )
+ {
+ buffer[i].Data = NULL;
+ buffer[i].Len = 0;
+ buffer[i].Size = 0;
+ buffer[i].IsDirty = true;
+ }
+ // Send scroll command to GUI
+ AxWin3_RichText_ScrollRange(gMainWindow, top, max, Count);
+
+ Display_int_SetCursor(Term, Term->CursorRow, Term->CursorCol);