News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Help with "center window over window" routine

Started by dacid, September 22, 2008, 04:35:10 PM

Previous topic - Next topic

dacid

I dont remember where i found this routine to center a window over other window:



dlgrect            RECT <?>
dlgrect2           RECT <?>

...

CenterWnd  PROC Dest:DWORD, Src:DWORD

          pushad

          invoke  GetWindowRect,Dest,addr dlgrect2
          invoke  GetWindowRect,Src,addr dlgrect

          mov     eax,dlgrect2.right
          sub     eax,dlgrect2.left
          push    eax
          mov     eax,dlgrect.right
          sub     eax,dlgrect.left
          pop     ebx
          sub     ebx,eax
          shr     ebx,1

          mov     eax,dlgrect2.bottom
          sub     eax,dlgrect2.top
          push    eax
          mov     eax,dlgrect.bottom
          sub     eax,dlgrect.top
          pop     ecx
          sub     ecx,eax
          shr     ecx,1

          push    0
          mov     edx,dlgrect.bottom
          sub     edx,dlgrect.top
          push    edx
          mov     edx,dlgrect.right
          sub     edx,dlgrect.left
          push    edx
          add     ecx,dlgrect2.top
          push    ecx
          add     ebx,dlgrect2.left
          push    ebx
          push    Src
          call    MoveWindow

          popad
          ret
         
CenterWnd  ENDP


The problem is when the the first window (parent) is smaller than the second one (the one to be centered)... it fails and the second window doesnt appears (or maybe is so small i cant see it). Can anyone help me to fix it?

Thx in advance!

PBrennick

dacid,

Give the following a try:

CenterWindow PROC p_hWndChild:DWORD, p_hWndParent:DWORD

   LOCAL l_rectChild:RECT         ; Child window coordonate
   LOCAL l_rectParent:RECT        ; Parent window coordonate
   LOCAL l_rectDesktop:RECT       ; Desktop coordonate (WORKAREA)

   invoke GetWindowRect, p_hWndChild, addr l_rectChild
   .if (eax != 0)    ; 0 = no centering possible

       invoke SystemParametersInfoA, SPI_GETWORKAREA, NULL, addr l_rectDesktop, NULL
       .if (eax != 0)    ; 0 = no centering possible

           invoke GetWindowRect, p_hWndParent, addr l_rectParent
           .if (eax == 0)    ; 0 = we take the desktop as parent (invalid or NULL hWndParent)

               mov eax, l_rectDesktop.left
               mov l_rectParent.left, eax
               mov eax, l_rectDesktop.top
               mov l_rectParent.top, eax
               mov eax, l_rectDesktop.right
               mov l_rectParent.right, eax
               mov eax, l_rectDesktop.bottom
               mov l_rectParent.bottom, eax

           .endif

           ;
           ; edi,esi : child window new x,y coordonate
           ;
           push edi
           push esi
           ;
           ; Get new coordonate and make sure the child window
           ; is not moved outside the desktop workarea
           ;
           mov eax, l_rectChild.right
           sub eax, l_rectChild.left                      ;
           mov ecx, eax                                   ; ecx = child width = right - left
           mov eax, l_rectParent.right
           sub eax, l_rectParent.left
           sub eax, ecx                                   ; eax = Parent width - Child width...
           sar eax, 1                                     ; divided by 2
           add eax, l_rectParent.left                     ; eax = temporary left coord (need validation)
           .if (sdword ptr eax < l_rectDesktop.left)
               mov eax, l_rectDesktop.left
           .endif
           mov edi, eax
           add eax, ecx                                   ; eax = new left coord + child width
           .if (sdword ptr eax > l_rectDesktop.right)     ; if child right outside desktop workarea...
               mov edi, l_rectDesktop.right
               sub edi, ecx                               ; right = desktop right - child width
           .endif

           mov eax, l_rectChild.bottom
           sub eax, l_rectChild.top                       ;
           mov ecx, eax                                   ; ecx = child height = bottom - top
           mov eax, l_rectParent.bottom
           sub eax, l_rectParent.top
           sub eax, ecx                                   ; eax = Parent height - Child height...
           sar eax, 1
           add eax, l_rectParent.top
           .if (sdword ptr eax < l_rectDesktop.top)       ; eax (child top) must not be smaller, if so...
               mov eax, l_rectDesktop.top                 ; child top = Desktop.top
           .endif
           mov esi, eax
           add eax, ecx                                   ; eax = new top coord + child height
           .if (sdword ptr eax > l_rectDesktop.bottom)
               mov esi, l_rectDesktop.bottom              ; child is outside desktop bottom
               sub esi, ecx                               ; child top = Desktop.bottom - child height
           .endif

           ;
           ; Now we have the new coordonate - the dialog window can be moved
           ;
           invoke SetWindowPos, p_hWndChild, NULL, edi, esi, NULL, NULL,
                               (SWP_NOSIZE or SWP_NOZORDER or SWP_NOCOPYBITS)
           pop esi
           pop edi

           ret

       .endif

   .endif

   xor eax, eax
   ret

CenterWindow ENDP


-- Paul
The GeneSys Project is available from:
The Repository or My crappy website


jdoe


dacid,

The procedure Paul has posted above (from GeneSys) also have the advantage that the child window is never shown outside the desktop.

:U


PBrennick

dacid,

JDoe has stated it perfectly. a lot of people contributed lots of very useful procedures which have become part of the GeneSys library. It is possible that you might want to download and explore what Genesys has to offer. It is not as powerful an SDK as masm32 but it does the job. Myself, I have both on my machine, always have. That particular procedure was donated by Philippe Coloumbe. A siimpler version that I often use to just center a window without reference to the location of the parent is as follows:

CenterWindow proc hWin:DWORD
;---------------------------------------
    LOCAL   Wtx :DWORD
    LOCAL   Wty :DWORD
    LOCAL   Wwd :DWORD
    LOCAL   Wht :DWORD
    LOCAL   rect:RECT

    invoke  GetWindowRect, hWin, addr rect
    mov     eax, rect.right
    sub     eax, rect.left
    mov     Wwd, eax
    mov     eax, rect.bottom
    sub     eax, rect.top
    mov     Wht, eax
    invoke  GetSystemMetrics, SM_CXSCREEN
    shr     eax, 1                      ; divide screen X by 2
    mov     ebx, Wwd                    ; Get window X value
    shr     ebx, 1                      ; divide window X by 2
    sub     eax, ebx                    ; sub half win X from half screen X
    mov     Wtx, eax
    invoke  GetSystemMetrics, SM_CYSCREEN
    shr     eax, 1                      ; divide screen Y by 2
    mov     ebx, Wht                    ; Get window Y value
    shr     ebx, 1                      ; divide window Y by 2
    sub     eax, ebx                    ; sub half win Y from half screen Y
    mov     Wty, eax
    invoke  SetWindowPos, hWin, 0, Wtx, Wty, 0, 0, SWP_NOZORDER or SWP_NOSIZE
    ret
;---------------------------------------
CenterWindow endp


Donated by Jake Commander.

-- Paul
The GeneSys Project is available from:
The Repository or My crappy website

jdoe


Paul,

I don't remember which one but I came across a problem with SetWindowPos and I had to use MoveWindow instead... another usefull code comment that I forgot to write   :(



;
; Centers a window into another one (do not display child outside desktop workarea)
;
; Returns non-zero if successful
;
; p_hWndChild  = Child window handle
; p_hWndParent = Parent window handle or NULL for desktop
;
AzmtCenterWindow PROC USES edi p_hWndChild:DWORD, p_hWndParent:DWORD

    LOCAL l_rectChild:RECT          ; Child window coordonate
    LOCAL l_rectParent:RECT         ; Parent window coordonate
    LOCAL l_rectDesktop:RECT        ; Desktop coordonate (WORKAREA)

    invoke GetWindowRect, p_hWndChild, addr l_rectChild
    test eax, eax
    jz @E                           ; 0 = no centering possible

    invoke SystemParametersInfoA, SPI_GETWORKAREA, NULL, addr l_rectDesktop, NULL
    test eax, eax
    jz @E                           ; 0 = no centering possible

    invoke GetWindowRect, p_hWndParent, addr l_rectParent
    test eax, eax
    jnz @F                          ; 0 = we take the desktop as parent (invalid or NULL hWndParent)

    mov eax, l_rectDesktop.left
    mov ecx, l_rectDesktop.top
    mov edx, l_rectDesktop.right
    mov edi, l_rectDesktop.bottom
    mov l_rectParent.left, eax
    mov l_rectParent.top, ecx
    mov l_rectParent.right, edx
    mov l_rectParent.bottom, edi

@@:
    ;
    ; edx = child window new x coordonate
    ; edi = child window new y coordonate
    ;

    push TRUE                       ;;;;;; bRepaint (sixth parameter of MoveWindow)

    mov eax, l_rectChild.bottom
    sub eax, l_rectChild.top
    mov ecx, eax                    ; ecx = child height = bottom - top
    push eax                        ;;;;;; nHeight (fifth parameter of MoveWindow)
    mov eax, l_rectParent.bottom
    sub eax, l_rectParent.top
    sub eax, ecx                    ; eax = Parent height - Child height...
    sar eax, 1
    add eax, l_rectParent.top
    cmp eax, l_rectDesktop.top
    jnl @F                          ; eax (child top) must not be smaller, if so...
    mov eax, l_rectDesktop.top      ; child top = Desktop.top
@@:
    mov edi, eax
    add eax, ecx                    ; eax = new top coord + child height
    cmp eax, l_rectDesktop.bottom
    jng @F
    mov edi, l_rectDesktop.bottom   ; child is outside desktop bottom
    sub edi, ecx                    ; child top = Desktop.bottom - child height

@@:
    mov eax, l_rectChild.right
    sub eax, l_rectChild.left
    mov ecx, eax                    ; ecx = child width = right - left
    push eax                        ;;;;;; nWidth (fourth parameter of MoveWindow)
    mov eax, l_rectParent.right
    sub eax, l_rectParent.left
    sub eax, ecx                    ; eax = Parent width - Child width...
    sar eax, 1                      ; divided by 2
    add eax, l_rectParent.left      ; eax = temporary left coord (need validation)
    cmp eax, l_rectDesktop.left
    jnl @F
    mov eax, l_rectDesktop.left
@@:
    mov edx, eax
    add eax, ecx                    ; eax = new left coord + child width
    cmp eax, l_rectDesktop.right
    jng @F                          ; if child right outside desktop workarea...
    mov edx, l_rectDesktop.right
    sub edx, ecx                    ; right = desktop right - child width

@@:
    push edi                        ;;;;;; Y (third parameter of MoveWindow)
    push edx                        ;;;;;; X (second parameter of MoveWindow)
    push p_hWndChild                ;;;;;; hWnd (first parameter of MoveWindow)
    call MoveWindow

@E:
    ret

AzmtCenterWindow ENDP



Philippe Coulombe... who is that guy ?   :wink


dacid

Sure i will download Genesys.. the original function works great here (Windows Vista x64 SP1) .. do you remember anything about the bug/problem jdoe?


PBrennick

JDoe,
The problem only occurs with MessageBoxes which are not very versatile anyway.

dacid,
Various people send me stuff using either their screen name or there real name or even both. Whenever I receive only one it implies to me that the person does not want the association to be revealed. I never violate this trust. I will say this, Philippe has been visiting the board in the past few days and may have read this post. If he wants to tell you, he will.

The same goes for Jake Commander, no one knows who he really is.

-- Paul
The GeneSys Project is available from:
The Repository or My crappy website

jdoe

Quote from: PBrennick on September 23, 2008, 02:59:49 PM
The problem only occurs with MessageBoxes which are not very versatile anyway.

Yeah I know... I use one CenterWindow procedure for all centering and using MoveWindow was more problem free for me. But SetWindowPos sure do the job for most case.


Quote from: PBrennick on September 23, 2008, 02:59:49 PM
Whenever I receive only one it implies to me that the person does not want the association to be revealed.

It's not that I mind about my real name... I was refering to the typo you made "Coloumbe". That's why I used the "wink" emoticon.

No offense

Have a good day

:U


dacid

mm .. if jdoes routine work in most cases maybe i should use it  :green2

anyways how do you center a messagebox?

PBrennick

dacid,
I agree with you, JDoe is a very good coder and it is wise to listen to his advice.

JDoe,
That is too funnjy. Actually, I was half asleep when I read that post and I thought it was dacid asking the question so that is why I answerred as I did. As far as the typo goes, lately, it seems to be par for the course for me. I wish I knew how to add a spell check to my editor. I suppose it would not be too hard to code it but where to get the database. It would probably have to be a CSV file for it to interest me (or a compressed version of one). I have zero interest in SQL, MySQL or YourSQL, etc.   :bg

Anyway, I type most responses in my editor so I can save them and then paste them here. The dictionary here is frustrating as it knows nothing about technical words and there is no way to add them. For some reason, it accepts 'MySQL' but does not understand 'SQL'?!?

BTW, dacid, to answer your question about centerring a MessageBox, why don't you follow the link JDoe posted? The example is there.

-- Paul
The GeneSys Project is available from:
The Repository or My crappy website