Такой эффект очень часто используется в различных кейгенах, окнах "О программе", демо-роликах, просмотрщиках текстовых файлов и подобных программах. Код основан на аналогичной процедуре от Av0id, я добавил в него несколько усовершенствований. Для настройки размеров и внешнего вида скроллера в сегменте данных определяются вспомогательные константы и структуры, не описанные в FASM:
; Настройки внешнего вида скроллера
SCROLL_FONT_WIDTH = 8 ; Ширина символов текста
SCROLL_FONT_HEIGHT = 8 ; Высота символов текста
SCROLL_WIDTH = 430 ; Ширина окна скроллера
SCROLL_HEIGHT = 350 ; Высота окна скроллера
SCROLL_BACKCOLOR = 0808080h ; Цвет фона
SCROLL_TEXTCOLOR = 000FFFFh ; Цвет текста
SCROLL_SHADOWCOLOR = 0 ; Цвет тени
SCROLL_SLEEP = 40 ; Скорость скроллирования
SCROLL_SHADOW = FALSE ; Рисовать тень TRUE/FALSE
; Структуры для создания виртуального BMP-файла
struct RGBQUAD
rgbBlue db ?
rgbGreen db ?
rgbRed db ?
rgbReserved db ?
ends
struct BITMAPINFO
bmiHeader BITMAPINFOHEADER
bmiColors RGBQUAD
ends
А также переменные и другие данные, необходимые для его работы:
section '.data' data readable writeable
hThread dd ? ; Хэндл потока скроллера
exit_flag dd ? ; Флаг завершения потока
active_flag dd ? ; Флаг активности скроллера
szTerminalFont db 'Terminal',0 ; Шрифт скроллера
; Файл с текстом скроллера
szScrollerText file 'scroller.txt'
db 0
Если в скроллере используется псевдографика, то желательно оставить шрифт "Terminal", а если будет только текст, то можете выбрать любой другой системный шрифт, лишь бы он был установлен у пользователя на компьютере. Текст скроллера можно создавать в любом редакторе, поддерживающем псевдографику. При использовании рамок или рисунков из символов, они обязательно должны быть дополнены пробелами до правой границы текста. Ширина и высота символов задается в настройках, но имейте в виду, что размеры должны поддерживаться свойствами самого шрифта. Поэкспериментируйте.
Запуск скроллера выполняется в отдельном окне, отдельным потоком. При этом свойства окна прописываются в ресурсах, а его размер подгоняется под размер, описанный в настройках скроллера.
...
; Инициализация окна скроллера
cmp [wMsg],WM_INITDIALOG
je .wminit
...
.wminit:
; Флаг завершения потока скроллера
mov [exit_flag],FALSE
; Подогнать размеры окна под размер скроллера
invoke SetWindowPos,[hWnd],NULL,NULL,NULL,SCROLL_WIDTH,\
SCROLL_HEIGHT,SWP_NOACTIVATE+SWP_NOZORDER+SWP_NOMOVE
; Запустить скроллер
invoke CreateThread,NULL,NULL,VerticalScrollShadow,\
[hWnd],NULL,NULL
; Сохранить хэндл потока
mov [hThread],eax
; Установить приоритет потока скроллера
invoke SetThreadPriority,eax,THREAD_BASE_PRIORITY_MAX
А вот и сама процедура скроллера. Принцип ее работы ненамного отличается от горизонтального скроллера. Точно так же текст преобразуется в картинку, а затем на фон из этой картинки в цикле накладывается "кадр" со сдвигом. Если задана тень, то сперва на фон накладывается тот же текст, но темного цвета и со смещением в несколько пикселов для создания нужного визуального эффекта. При достижении конца текста он "перематывается" на начало.
;---------------------------------------------------
; Процедура вертикального скроллера текста в окне
; На основе кода от Av0id
;---------------------------------------------------
proc VerticalScrollShadow hWnd:DWORD
; Локальные переменные
locals
hDC dd ?
hCompatDC dd ?
hCompatDC2 dd ?
hFont dd ?
hLen dd ?
hTextHeight dd ?
hDIBits dd ?
hDIBits2 dd ?
hDIBSection dd ?
hDIBSection2 dd ?
hBrush dd ?
dStep dd ?
dPos dd ?
rct RECT
bmi BITMAPINFO
endl
pusha
xor ebx,ebx
invoke GetDC,[hWnd]
mov [hDC],eax
invoke CreateCompatibleDC,eax
mov [hCompatDC],eax
invoke CreateCompatibleDC,[hDC]
mov [hCompatDC2],eax
; Моноширинный шрифт Terminal
invoke CreateFont,SCROLL_FONT_WIDTH,SCROLL_FONT_HEIGHT,\
ebx,ebx,FW_NORMAL,ebx,ebx,ebx,OEM_CHARSET,ebx,ebx,\
ebx,ebx,szTerminalFont
mov [hFont],eax
invoke SelectObject,[hCompatDC],eax
; Вычислить размеры блока текста
xor esi,esi
dec esi
mov edi,szScrollerText
invoke lstrlen,edi
inc eax
mov [hLen],eax
mov ecx,eax
; Количество строк равно количеству символов переноса строки
mov al,13
@@:
inc esi
repne scasb
jz @b
; Высота картинки равна количеству строк * высоту шрифта
xor edx,edx
mov eax,SCROLL_FONT_HEIGHT
imul esi
add eax,SCROLL_HEIGHT
mov [hTextHeight],eax
; Создать виртуальный BMP-файл с нарисованным текстом
lea edi,[bmi]
mov [edi+BITMAPINFO.bmiHeader.biSize],sizeof.BITMAPINFOHEADER
mov [edi+BITMAPINFO.bmiHeader.biWidth],SCROLL_WIDTH
mov eax,[hTextHeight]
not eax
mov [edi+BITMAPINFO.bmiHeader.biHeight],eax
mov [edi+BITMAPINFO.bmiHeader.biPlanes],1
mov [edi+BITMAPINFO.bmiHeader.biBitCount],24
lea eax,[hDIBits]
invoke CreateDIBSection,[hCompatDC],edi,ebx,eax,ebx,ebx
mov [hDIBSection],eax
mov [edi+BITMAPINFO.bmiHeader.biHeight],SCROLL_HEIGHT
lea eax,[hDIBits2]
invoke CreateDIBSection,[hCompatDC2],edi,ebx,eax,ebx,ebx
mov [hDIBSection2],eax
invoke SelectObject,[hCompatDC],[hDIBSection]
invoke SelectObject,[hCompatDC2],[hDIBSection2]
; Размеры области заливки
lea edi,[rct]
mov [edi+RECT.top],0
mov [edi+RECT.left],0
mov ecx,[hTextHeight]
add ecx,SCROLL_HEIGHT
mov [edi+RECT.bottom],ecx
mov [edi+RECT.right],SCROLL_WIDTH
; Заливка фона
invoke CreateSolidBrush,SCROLL_BACKCOLOR
mov [hBrush],eax
invoke FillRect,[hCompatDC],edi,[hBrush]
invoke FillRect,[hCompatDC2],edi,[hBrush]
; Режим отображения - прозрачный
invoke SetBkMode,[hCompatDC],TRANSPARENT
; Рисовать текст с тенью?
mov eax,SCROLL_SHADOW
cmp eax,FALSE
je @f
; Установить координаты сдвига для тени
mov [edi+RECT.top],1
mov [edi+RECT.left],2
; Нарисовать подложку тени со сдвигом
invoke SetTextColor,[hCompatDC],SCROLL_SHADOWCOLOR
invoke DrawText,[hCompatDC],szScrollerText,[hLen],edi,1
@@:
; Координаты вывода нормального текста
mov [edi+RECT.top],0
mov [edi+RECT.left],0
; Нарисовать основной текст
invoke SetTextColor,[hCompatDC],SCROLL_TEXTCOLOR
invoke DrawText,[hCompatDC],szScrollerText,[hLen],edi,1
mov esi,SCROLL_HEIGHT
not esi
.reset:
mov edi,esi
.paint:
; Отрисовка картинки со сдвигом
invoke BitBlt,[hCompatDC2],ebx,ebx,SCROLL_WIDTH,SCROLL_HEIGHT,\
[hCompatDC],ebx,edi,SRCCOPY
invoke BitBlt,[hDC],ebx,ebx,SCROLL_WIDTH,SCROLL_HEIGHT,\
[hCompatDC2],ebx,ebx,SRCCOPY
; Таймаут
invoke Sleep,SCROLL_SLEEP
; Картинка прокручена до конца?
inc edi
mov eax,[hTextHeight]
sub eax,SCROLL_HEIGHT
cmp eax,edi
jz .reset
; Флаг выхода установлен?
cmp [exit_flag],1
jnz .paint
.exit:
; Прибраться за собой и завершить поток
invoke DeleteObject,[hBrush]
invoke DeleteObject,[hDIBSection]
invoke DeleteObject,[hDIBSection2]
invoke DeleteObject,[hFont]
invoke DeleteDC,[hCompatDC]
invoke DeleteDC,[hCompatDC2]
invoke ReleaseDC,[hWnd],[hDC]
invoke ExitThread,ebx
popa
ret
endp