; $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
; $     Автор Чеботарёв А.М. (Chib777)                                    $
; $     chib_odessa@bk.ru                                                 $
; $     chib_odessa@ua.fm                                                 $
; $     16 \\ 01 \\ 2004                                                  $
; $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

      .586                      ; create 32 bit code
      .model flat, stdcall      ; 32 bit memory model
      option casemap :none      ; case sensitive
      include Scroll_1.inc        ; local includes for this file

.code

; #########################################################################

start:

        mov hInstance, $invoke (GetModuleHandle, NULL)
        invoke InitCommonControls

        call Main
        invoke ExitProcess,eax

; #########################################################################

Main proc

        ;====================
        ; Put LOCALs on stack
        ;====================

        LOCAL wc   :WNDCLASSEX
        LOCAL msg  :MSG

        LOCAL Wwd  :DWORD
        LOCAL Wht  :DWORD
        LOCAL Wtx  :DWORD
        LOCAL Wty  :DWORD

        ;==================================================
        ; Fill WNDCLASSEX structure with required variables
        ;==================================================

        mov wc.cbSize,         sizeof WNDCLASSEX
        mov wc.style,          CS_HREDRAW or CS_VREDRAW \
                               or CS_BYTEALIGNWINDOW
        mov wc.lpfnWndProc,    offset WndProc
        mov wc.cbClsExtra,     NULL
        mov wc.cbWndExtra,     NULL
        m2m wc.hInstance,      hInstance
        mov wc.hbrBackground,  COLOR_GRAYTEXT
        mov wc.lpszMenuName,   NULL
        mov wc.lpszClassName,  offset szClassName
        mov wc.hIcon, $invoke (LoadIcon,NULL,IDI_APPLICATION)
        mov wc.hCursor, $invoke (LoadCursor,NULL,IDC_ARROW)
        mov wc.hIconSm, 0

        invoke RegisterClassEx, ADDR wc

        ;================================
        ; Centre window at following size
        ;================================

        mov Wwd, 700
        mov Wht, 500

        invoke GetSystemMetrics,SM_CXSCREEN
        mov Wtx, $invoke (TopXY,Wwd,eax)

        invoke GetSystemMetrics,SM_CYSCREEN
        mov Wty, $invoke (TopXY,Wht,eax)

  ; -------------------------------------------------
        invoke LoadMenuA , hInstance, 600

        invoke CreateWindowEx,WS_EX_CLIENTEDGE,
                              ADDR szClassName,
                              ADDR szDisplayName,
                              WS_OVERLAPPEDWINDOW or WS_VISIBLE  or WS_VSCROLL or WS_HSCROLL,
                              Wtx,Wty,Wwd,Wht,
                              NULL,eax,
                              hInstance,NULL
        mov   hWnd,eax

      ;===================================
      ; Loop until PostQuitMessage is sent
      ;===================================

    StartLoop:
      invoke GetMessage,ADDR msg,NULL,0,0
      cmp eax, 0
      je ExitLoop
      invoke TranslateMessage, ADDR msg
      invoke DispatchMessage,  ADDR msg
      jmp StartLoop
    ExitLoop:

      return msg.wParam

Main endp

; #########################################################################

WndProc proc hWin :DWORD, uMsg :DWORD, wParam :DWORD, lParam :DWORD

    LOCAL hDC :HDC
    LOCAL ddbinfo   :BITMAP

    .if uMsg == WM_COMMAND

        .if wParam == IDM_OPEN

            ; --------------------------------------
            ; szFileName is defined in Filedlgs.asm
            ; --------------------------------------
            mov szFileName[0],0     ; set 1st byte to zero
            invoke GetFileName,hWin,ADDR szOpenTitle,ADDR szFilter
            cmp szFileName[0],0     ; zero if cancel pressed in dlgbox
            je @F
                  ; ---------------------------------
                  ; КОД ЗАГРУЗКИ
                  ; ---------------------------------
            .if hBitmapOld     ; УДАЛИМ РАСТР ИЗ КОНТЕКСТА ЕСЛИ ОН ЗАГРУЖЕН
                invoke SelectObject, hMemDC, hBitmapOld ; исключим hBitmap
                invoke DeleteObject, eax                ; удалим текущий растр
            .endif

            mov hBitmap, $invoke (LoadImage ,hInstance, ADDR szFileName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE)
            mov hBitmapOld, $invoke (SelectObject, hMemDC, hBitmap)

            invoke GetObject, hBitmap, sizeof(BITMAP), ADDR ddbinfo    ; ПОЛУЧИМ ИНФОРМАЦИЮ О DDB - РАСТРЕ

            m2m nWidth, ddbinfo.bmWidth                ; ШИРИНА
            m2m nHeight, ddbinfo.bmHeight              ; ВЫСОТА

            mov fScroll, TRUE
            invoke InvalidateRect, hWin, NULL, FALSE    ;Генерация сообщения WM_PAINT
            @@:

        .elseif wParam == IDM_EXIT  ; ВЫХОД

            invoke SendMessage,hWin,WM_SYSCOMMAND,SC_CLOSE,NULL

        .elseif wParam == IDM_ABOUT ; О ПРОГРАММЕ

            invoke DialogBoxParamA, hInstance, IDD_ABOUT, hWin, AboutProc, NULL

        .endif

    .elseif uMsg == WM_CREATE

            ; СОЗДАДИМ СОВМЕСТИМЫЙ КОНТЕКСТ УСТРОЙСТВА
            mov hDC, $invoke( GetDC, hWin )
            mov hMemDC,$invoke ( CreateCompatibleDC, hDC )
            invoke ReleaseDC, hWin, hDC

    .elseif uMsg == WM_SIZE

        mov fScroll, TRUE
        invoke InvalidateRect, hWin, NULL, FALSE    ;Генерация сообщения WM_PAINT
 
    .elseif uMsg == WM_VSCROLL
    LOWORD wParam

    .if eax == SB_LINEDOWN            ; User clicked the right arrow. 
    
        mov eax, nVertDiff
        .if nVertPos < eax

            mov eax, nHeight
            invoke IntDiv, eax, 100   ; размер приращения (строки) = 1/100 размера документа (растра)
            .if eax < 1               ; На случай если растр сильно маленький, что бы приращение не равнялось 0
              inc eax
            .endif
          add nVertPos, eax

        .endif

    .elseif eax == SB_LINEUP          ; User clicked the left arrow.  
    
        .if nVertPos > 0

            mov eax, nHeight
            invoke IntDiv, eax, 100   ; размер приращения (строки) = 1/100 размера документа (растра)
            .if eax < 1               ; На случай если растр сильно маленький, что бы приращение не равнялось 0
              inc eax
            .endif
          sub nVertPos, eax

        .endif

    .elseif eax == SB_PAGEUP          ; User clicked the shaft left of the scroll box.   

        .if nVertPos > 0

            mov eax, nHeight
            invoke IntDiv, eax, 10    ; размер приращения (страницы) = 1/10 размера документа (растра)
            .if eax < 1               ; На случай если растр сильно маленький, что бы приращение не равнялось 0
              inc eax
            .endif
          sub nVertPos, eax

        .endif

    .elseif eax == SB_PAGEDOWN        ; User clicked the shaft right of the scroll box.

        mov eax, nVertDiff
        .if nVertPos < eax

            mov eax, nHeight
            invoke IntDiv, eax, 10    ; размер приращения (строки) = 1/10 размера документа (растра)
            .if eax < 1               ; На случай если растр сильно маленький, что бы приращение не равнялось 0
              inc eax
            .endif
          add nVertPos, eax

        .endif

    .elseif ( eax == SB_THUMBTRACK ) || ( eax == SB_THUMBPOSITION ) ; User dragged the scroll box.
        HIWORD wParam
        mov nVertPos, ebx
    .endif

     invoke SetScrollPos,hWin, SB_VERT, nVertPos, TRUE  ; Reset the scroll bar.
     mov fScroll, FALSE
     invoke InvalidateRect, hWin, NULL, FALSE

    .elseif uMsg == WM_HSCROLL
    LOWORD wParam

    .if eax == SB_LINERIGHT           ; User clicked the right arrow. 
        mov eax, nHorizDiff
        .if nHorizPos < eax

            mov eax, nWidth
            invoke IntDiv, eax, 100   ; размер приращения (строки) = 1/100 размера документа (растра)
            .if eax < 1               ; На случай если растр сильно маленький, что бы приращение не равнялось 0
              inc eax
            .endif
          add nHorizPos, eax

        .endif

    .elseif eax == SB_LINELEFT        ; User clicked the left arrow.

        .if nHorizPos > 0

            mov eax, nWidth
            invoke IntDiv, eax, 100   ; размер приращения (строки) = 1/100 размера документа (растра)
            .if eax < 1               ; На случай если растр сильно маленький, что бы приращение не равнялось 0
              inc eax
            .endif
          sub nHorizPos, eax

        .endif

    .elseif eax == SB_PAGERIGHT       ; User clicked the shaft left of the scroll box.  

        mov eax, nHorizDiff
        .if nHorizPos < eax

            mov eax, nWidth
            invoke IntDiv, eax, 10    ; размер приращения (строки) = 1/10 размера документа (растра)
            .if eax < 1               ; На случай если растр сильно маленький, что бы приращение не равнялось 0
              inc eax
            .endif
          add nHorizPos, eax

        .endif

    .elseif eax == SB_PAGELEFT        ; User clicked the shaft right of the scroll box.

        .if nHorizPos > 0

            mov eax, nWidth
            invoke IntDiv, eax, 10    ; размер приращения (строки) = 1/10 размера документа (растра)
            .if eax < 1               ; На случай если растр сильно маленький, что бы приращение не равнялось 0
              inc eax
            .endif
          sub nHorizPos, eax

        .endif
        
    .elseif ( eax == SB_THUMBTRACK ) || ( eax == SB_THUMBPOSITION ) ; User dragged the scroll box.

        HIWORD wParam
        mov nHorizPos, ebx
        
    .endif     

    invoke SetScrollPos,hWin, SB_HORZ, nHorizPos, TRUE  ; Reset the scroll bar.
    mov fScroll, FALSE
    invoke InvalidateRect, hWin, NULL, FALSE

    .elseif uMsg == WM_PAINT
        invoke Paint_Proc,hWin
        return 0

    .elseif uMsg == WM_CLOSE

    .elseif uMsg == WM_DESTROY

       .if hBitmapOld           ; ОСВОБОДИМ ПАМЯТЬ ЗАНИМАЕМУЮ РАСТРОМ, ЕСЛИ ОН ЗАГРУЖЕН.
        invoke SelectObject, hMemDC, hBitmapOld ; исключим hBitmap
        invoke DeleteObject, eax                ; удалим текущий растр
       .endif

        invoke DeleteDC, hMemDC                 ; освободим ресурсы
        invoke PostQuitMessage,NULL
        return 0

    .endif

def_window_proc:

    invoke DefWindowProc,hWin,uMsg,wParam,lParam

    ret

WndProc endp

; ########################################################################

Paint_Proc proc hWin:DWORD

    LOCAL hDC   :HDC
    LOCAL Ps    :PAINTSTRUCT
    LOCAL lpSi  :SCROLLINFO
    LOCAL rect      :RECT

    mov hDC, $invoke (BeginPaint,hWin,ADDR Ps)

    invoke GetClientRect, hWin, ADDR rect

    .if fScroll

	; ГОРИЗОНТАЛЬНАЯ ЛИНЕЙКА ПРОКРУТКИ
	    m2m nHorizDiff, nWidth
	    mov eax, rect.right
	    sub nHorizDiff, eax
	;--------------------------------
	    mov eax, nWidth
	
	    .if rect.right < eax    ;отображать линейки прокрутки
	
	        mov lpSi.cbSize, sizeof(SCROLLINFO)
	        mov lpSi.fMask, SIF_RANGE or SIF_PAGE
	        m2m lpSi.nMin, 0    ; Минимальное значение диапахона прокрутки
	        dec eax
	        mov lpSi.nMax, eax  ; Максимальное значение диапахона прокрутки
	        m2m lpSi.nPage, rect.right
	
	        invoke SetScrollInfo, hWin, SB_HORZ, ADDR lpSi, TRUE
	
	    .else           ;не отображать линейки прокрутки
	        invoke SetScrollRange, hWin, SB_HORZ, 0, 0, TRUE
	    .endif
	
	; ВЕРТИКАЛЬНАЯ ЛИНЕЙКА ПРОКРУТКИ
	    m2m nVertDiff, nHeight
	    mov eax, rect.bottom
	    sub nVertDiff, eax
	;--------------------------------
	    mov eax, nHeight
	
	    .if rect.bottom < eax
	
	        mov lpSi.cbSize, sizeof(SCROLLINFO)
	        mov lpSi.fMask, SIF_RANGE or SIF_PAGE
	        m2m lpSi.nMin, 0        ; Минимальное значение диапахона прокрутки
	        dec eax                 ; ДИАПАЗОН ПРОКРУТКИ [Min;Max-1], поэтому вычитаем 1
	        mov lpSi.nMax, eax      ; Максимальное значение диапахона прокрутки
	        m2m lpSi.nPage, rect.bottom ; РАЗМЕР СТРАНИЦЫ ДОЛЖЕН НАМОДИТЬСЯ МЕЖДУ nMin и nMax
	
	        invoke SetScrollInfo, hWin, SB_VERT, ADDR lpSi, TRUE
	
	    .else
	        invoke SetScrollRange, hWin, SB_VERT, 0, 0, TRUE        ;не отображать линейки прокрутки
	    .endif

     mov fScroll, FALSE
	    
    .endif   

; ----------------------------------------
    mov ebx, $invoke (GetScrollPos, hWin, SB_HORZ)
    invoke GetScrollPos, hWin, SB_VERT
    invoke BitBlt, hDC, 0, 0, rect.right, rect.bottom, hMemDC, ebx, eax, SRCCOPY
; ----------------------------------------

    invoke EndPaint,hWin,ADDR Ps

    ret

Paint_Proc endp

; ########################################################################

TopXY proc wDim:DWORD, sDim:DWORD

    shr sDim, 1      ; divide screen dimension by 2
    shr wDim, 1      ; divide window dimension by 2
    mov eax, wDim    ; copy window dimension into eax
    sub sDim, eax    ; sub half win dimension from half screen dimension

    return sDim

TopXY endp

; ########################################################################

AboutProc proc hWin :DWORD, uMsg :DWORD, wParam :DWORD, lParam :DWORD
    
   .if  (uMsg == WM_COMMAND && wParam == IDOK) || uMsg == WM_CLOSE
    
        invoke EndDialog, hWin, 0
        return TRUE
                
   .endif
    
    xor eax, eax    
    ret
    
AboutProc endp

; ########################################################################

end start