Sourcecode

;--------------------------------------------;
;                                            ;
; version:   0.2                             ;
; date:      26.10.2008                      ;
;                                            ;
; author:    raz@DIINGGENTLEMENTZ.COMputing  ;
; website:   www.diinggentlementz.com        ;
;                                            ;
; License:   Feel free to use, to modify and ;
;            to distribute the code in any   ;
;            way you want.                   ;
;            But just keep the original      ;
;            credits in the header.          ;
; USE IT AT YOUR OWN RISK! ;
;                                            ;
;--------------------------------------------;

; declares
Declare.l PureRESIZE_SetGadgetResize(paramActiveWindow.l, paramGadget.l, paramLeft.b = 0, paramTop.b = 0, paramRight.b = 0, paramBottom.b = 0)
Declare.l PureRESIZE_ClearGadgetResize(paramActiveWindow.l, paramGadget.l)
Declare.l PureRESIZE_CenterGadget(paramActiveWindow.l, paramGadget.l, paramCenterHorizontal.b = 0, paramCenterVertical.b = 0)
Declare.l PureRESIZE_SetWindowMinimumSize(paramActiveWindow.l , paramMinWidth.l, paramMinHeight.l)
Declare.l PureRESIZE_SetWindowMaximumSize(paramActiveWindow.l , paramMaxWidth.l, paramMaxHeight.l)
Declare.l PureRESIZE_UpdateResize()


; Windows-specific Definitions, so we need a compilerswitch
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
  ; declares
  Declare.l Windows_WindowCallback(WindowID, message, wParam, lParam)
  Declare.l Windows_GetTitleBarHeight(WindowHandle.l)
  ; constants
  #CCHILDREN_TITLEBAR = 5
  ; structures
  Structure CN_TITLEBARINFO
    cbSize.l
    rcTitleBar.RECT
    rgstate.l[#CCHILDREN_TITLEBAR+1]
  EndStructure
CompilerEndIf

; returncodes
#PureRESIZE_Ok = 1
#PureRESIZE_NotAGadget = 2 ; gadget is not valid
#PureRESIZE_NotAWindow = 3 ; window is not valid


Structure structResizeGadget
  lGadget.l
  lActiveWindow.l
  bLeft.b
  bTop.b
  bRight.b
  bBottom.b
  bCenterHorizontal.b
  bCenterVertical.b
  orgLeft.l
  orgTop.l
  orgRight.l
  orgBottom.l
  orgWidth.l
  orgHeight.l
  orgWindowHeight.l
  orgWindowWidth.l
  newLeft.l
  newTop.l
  newWidth.l
  newHeight.l
EndStructure

Structure structMinWindowSize
  lWindowID.l
  lMinWidth.l
  lMinHeight.l
  lMaxWidth.l
  lMaxHeight.l
EndStructure


Global NewList listResizeGadget.structResizeGadget()
Global NewList WindowSize.structMinWindowSize()


Procedure.l PureRESIZE_SetGadgetResize(paramActiveWindow.l, paramGadget.l, paramLeft.b = 0, paramTop.b = 0, paramRight.b = 0, paramBottom.b = 0)
  If Not IsGadget(paramGadget) : ProcedureReturn #PureRESIZE_NotAGadget : EndIf
  If Not IsWindow(paramActiveWindow) : ProcedureReturn #PureRESIZE_NotAWindow : EndIf
  AddElement(listResizeGadget())
  With listResizeGadget()
    \lGadget = paramGadget
    \lActiveWindow = paramActiveWindow
    \bLeft = paramLeft
    \bTop = paramTop
    \bRight = paramRight
    \bBottom = paramBottom
    \bCenterHorizontal = 0
    \bCenterVertical = 0
    \orgLeft = GadgetX(paramGadget)
    \orgTop = GadgetY(paramGadget)
    \orgRight = WindowWidth(paramActiveWindow) - GadgetX(paramGadget) - GadgetWidth(paramGadget)
    \orgBottom = WindowHeight(paramActiveWindow) - GadgetY(paramGadget) - GadgetHeight(paramGadget)
    \orgWidth = GadgetWidth(paramGadget)
    \orgHeight = GadgetHeight(paramGadget)
    \orgWindowHeight = WindowHeight(paramActiveWindow)
    \orgWindowWidth = WindowWidth(paramActiveWindow)
    \newLeft = #PB_Ignore
    \newTop = #PB_Ignore
    \newWidth = #PB_Ignore
    \newHeight = #PB_Ignore
  EndWith
  ProcedureReturn #PureRESIZE_Ok
EndProcedure

Procedure.l PureRESIZE_CenterGadget(paramActiveWindow.l, paramGadget.l, paramCenterHorizontal.b = 0, paramCenterVertical.b = 0)
  If Not IsGadget(paramGadget) : ProcedureReturn #PureRESIZE_NotAGadget : EndIf
  If Not IsWindow(paramActiveWindow) : ProcedureReturn #PureRESIZE_NotAWindow : EndIf
  AddElement(listResizeGadget())
  With listResizeGadget()
    \lGadget = paramGadget
    \lActiveWindow = paramActiveWindow
    \bLeft = 0
    \bTop = 0
    \bRight = 0
    \bBottom = 0
    \bCenterHorizontal = paramCenterHorizontal
    \bCenterVertical = paramCenterVertical
    \orgLeft = GadgetX(paramGadget)
    \orgTop = GadgetY(paramGadget)
    \orgRight = WindowWidth(paramActiveWindow) - GadgetX(paramGadget) - GadgetWidth(paramGadget)
    \orgBottom = WindowHeight(paramActiveWindow) - GadgetY(paramGadget) - GadgetHeight(paramGadget)
    \orgWidth = GadgetWidth(paramGadget)
    \orgHeight = GadgetHeight(paramGadget)
    \orgWindowHeight = WindowHeight(paramActiveWindow)
    \orgWindowWidth = WindowWidth(paramActiveWindow)
    \newLeft = #PB_Ignore
    \newTop = #PB_Ignore
    \newWidth = #PB_Ignore
    \newHeight = #PB_Ignore
  EndWith
  ProcedureReturn #PureRESIZE_Ok
EndProcedure

Procedure.l PureRESIZE_ClearGadgetResize(paramActiveWindow.l, paramGadget.l)
  If Not IsGadget(paramGadget) : ProcedureReturn #PureRESIZE_NotAGadget : EndIf
  If Not IsWindow(paramActiveWindow) : ProcedureReturn #PureRESIZE_NotAWindow : EndIf
  ForEach listResizeGadget()
    If listResizeGadget()\lGadget = paramGadget
      If listResizeGadget()\lActiveWindow = paramActiveWindow
        DeleteElement(listResizeGadget())
      EndIf
    EndIf
  Next
  ProcedureReturn #PureRESIZE_Ok
EndProcedure

Procedure.l PureRESIZE_SetWindowMinimumSize(paramActiveWindow.l , paramMinWidth.l, paramMinHeight.l)
  If Not IsWindow(paramActiveWindow) : ProcedureReturn #PureRESIZE_NotAWindow : EndIf
  Protected EntryExist.b = 0
  With WindowSize()
    ForEach WindowSize()
      If \lWindowID = paramActiveWindow
        EntryExist = 1
        Break
      EndIf
    Next
    If EntryExist = 0
      AddElement(WindowSize())
    EndIf
    \lWindowID = paramActiveWindow
    \lMinWidth = paramMinWidth
    \lMinHeight = paramMinHeight
  EndWith
 
  CompilerSelect #PB_Compiler_OS
   
    CompilerCase #PB_OS_Windows
        ; Set the Hook
        SetWindowCallback(@Windows_WindowCallback(), paramActiveWindow)
    CompilerCase #PB_OS_Linux
      ; Using only GTK!
      Protected pGeometry.GdkGeometry
      With pGeometry
        \min_width.l = WindowSize()\lMinWidth
        \min_height.l = WindowSize()\lMinHeight
        \max_width.l = WindowSize()\lMaxWidth
        \max_height.l = WindowSize()\lMaxHeight
     
        If \min_width And \min_height
          Statuscode.l | #GDK_HINT_MIN_SIZE
        EndIf
        If \max_width And \max_height
          Statuscode.l | #GDK_HINT_MAX_SIZE
        EndIf
      EndWith 
     
      gtk_window_set_geometry_hints_(WindowID(paramActiveWindow), 0, @pGeometry, Statuscode)
     
  CompilerEndSelect
  ProcedureReturn #PureRESIZE_Ok
EndProcedure

Procedure.l PureRESIZE_SetWindowMaximumSize(paramActiveWindow.l , paramMaxWidth.l, paramMaxHeight.l)
  If Not IsWindow(paramActiveWindow) : ProcedureReturn #PureRESIZE_NotAWindow : EndIf
  Protected EntryExist.b = 0
  With WindowSize()
    ForEach WindowSize()
      If \lWindowID = paramActiveWindow
        EntryExist = 1
        Break
      EndIf
    Next
    If EntryExist = 0
      AddElement(WindowSize())
    EndIf
    \lWindowID = paramActiveWindow
    \lMaxWidth = paramMaxWidth
    \lMaxHeight = paramMaxHeight
  EndWith
 
  CompilerSelect #PB_Compiler_OS
     
    CompilerCase #PB_OS_Windows
      ; set the Hook
      SetWindowCallback(@Windows_WindowCallback(), paramActiveWindow)
    CompilerCase #PB_OS_Linux
     
      Protected pGeometry.GdkGeometry
      With pGeometry
        \min_width.l = WindowSize()\lMinWidth
        \min_height.l = WindowSize()\lMinHeight
        \max_width.l = WindowSize()\lMaxWidth
        \max_height.l = WindowSize()\lMaxHeight
       
        If \min_width And \min_height
          Statuscode.l | #GDK_HINT_MIN_SIZE
        EndIf
        If \max_width And \max_height
          Statuscode.l | #GDK_HINT_MAX_SIZE
        EndIf
      EndWith
     
      gtk_window_set_geometry_hints_(WindowID(paramActiveWindow), 0, @pGeometry, Statuscode)
     
  CompilerEndSelect
  ProcedureReturn #PureRESIZE_Ok
EndProcedure

Procedure.l PureRESIZE_UpdateResize()
  ForEach listResizeGadget()
    With listResizeGadget()
     
      ; Update horizontal and vertical centering
      If \bCenterHorizontal = 1 And \bCenterVertical = 1
        \newLeft = ((WindowWidth(\lActiveWindow) / 2) - (\orgWidth / 2))
        \newTop = (WindowHeight(\lActiveWindow) / 2) - (\orgHeight )
      Else
        If \bCenterHorizontal = 1
          \newLeft = ((WindowWidth(\lActiveWindow) / 2) - (\orgWidth / 2))
          \newTop = \orgTop
        ElseIf \bCenterVertical = 1
          \newLeft = \orgLeft
          \newTop = (WindowHeight(\lActiveWindow) / 2) - (\orgHeight )
        Else
         
          ; Update Docking Left and Right
          If \bLeft = 1 And \bRight = 1
            \newLeft = \orgLeft
            \newWidth = WindowWidth(\lActiveWindow) - \orgRight - \orgLeft
          Else
            ; Update Docking Right
            If \bRight = 1
              \newLeft = WindowWidth(\lActiveWindow) - \orgRight - \orgWidth
              \newWidth = \orgWidth
              ; Update Docking Left
            ElseIf \bLeft = 1
              \newLeft = \orgLeft
              \newWidth = \orgWidth
            EndIf
          EndIf
         
          ; Update Docking Top and Bottom
          If \bTop = 1 And \bBottom = 1
            \newTop = \orgTop
            \newHeight = WindowHeight(\lActiveWindow) - \orgTop - \orgBottom
          Else
            ; Update Docking Bottom
            If \bBottom = 1
              \newTop = WindowHeight(\lActiveWindow) - \orgBottom - \orgHeight
              \newHeight = \orgHeight
              ; Update Docking Top
            ElseIf \bTop = 1
              \newTop = \orgTop
              \newHeight = \orgHeight
            EndIf
          EndIf
        EndIf
      EndIf
     
    EndWith
  Next
  ForEach listResizeGadget()
    With listResizeGadget()
      ResizeGadget(\lGadget, \newLeft, \newTop, \newWidth, \newHeight)
      ;reset values:
      \newLeft = #PB_Ignore
      \newTop = #PB_Ignore
      \newWidth = #PB_Ignore
      \newHeight = #PB_Ignore
    EndWith
  Next
  ProcedureReturn #PureRESIZE_Ok
EndProcedure


; Windows-specific Procedures, so we need a compilerswitch
CompilerIf #PB_Compiler_OS = #PB_OS_Windows

Procedure.l Windows_WindowCallback(WindowID, message, wParam, lParam)
  Protected Result = #PB_ProcessPureBasicEvents
  Select message
    Case #WM_GETMINMAXINFO
      ForEach WindowSize()
        With WindowSize()
          If WindowID = WindowID(\lWindowID)
            ; Purbasic's WindowHeight() and WindowWidth() only return the Size of the Workspace
            ; so we have to get the width and the height of the border of the window
            Protected lTitleBarHeight.l = Windows_GetTitleBarHeight(WindowID(\lWindowID))
            Protected lBorderWidth.l = 2
            Protected lBorderHeight.l = 2
            WindowInfo.WINDOWINFO
            WindowInfo\cbSize = SizeOf(WINDOWINFO)
            If GetWindowInfo_(WindowID, @WindowInfo)
              lBorderWidth.l = WindowInfo\cxWindowBorders
              lBorderHeight.l = WindowInfo\cyWindowBorders
            EndIf
           
            Protected *pMinMax.MINMAXINFO = lParam
            If \lMinWidth : *pMinMax\ptMinTrackSize\x = \lMinWidth + (2 * lBorderWidth): EndIf
            If \lMinHeight : *pMinMax\ptMinTrackSize\y = \lMinHeight + lTitleBarHeight + (2 * lBorderHeight) : EndIf
            If \lMaxWidth : *pMinMax\ptMaxTrackSize\x = \lMaxWidth + (2 * lBorderWidth): EndIf
            If \lMaxHeight : *pMinMax\ptMaxTrackSize\y = \lMaxHeight + lTitleBarHeight + (2 * lBorderHeight) : EndIf
          EndIf
        EndWith
      Next
      Result = 0
     
    ; On Close remove the hook
    Case #WM_CLOSE
      ForEach WindowSize()
        With WindowSize()
          If WindowID = WindowID(\lWindowID)
            SetWindowCallback(0 , \lWindowID)
          EndIf
        EndWith
      Next
  EndSelect
  ProcedureReturn Result
EndProcedure

Procedure.l Windows_GetTitleBarHeight(WindowHandle.l)  ; Returns the Titlebar height
  title.CN_TITLEBARINFO
  title\cbSize = SizeOf(CN_TITLEBARINFO)
  title\rgstate = 0
  GetTitleBarInfo_(WindowHandle,@title)
  top_pos = title\rcTitleBar\top
  bottom_pos = title\rcTitleBar\bottom
  titlebarheight = bottom_pos - top_pos
  ProcedureReturn titlebarheight
EndProcedure

CompilerEndIf