Gadget Dock Include

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
HeX0R
Beiträge: 3042
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win11 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2 + 3
Kontaktdaten:

Beitrag von HeX0R »

Kiffi hatte doch soetwas in der Art schon mal angefangen (*denk*)

[Edit]
Ah da
Benutzeravatar
Kiffi
Beiträge: 10714
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Beitrag von Kiffi »

HeX0R hat geschrieben:Kiffi hatte doch soetwas in der Art schon mal angefangen (*denk*)
lässt sich nicht ganz vergleichen, denn das Docking hat in diesem Fall DotNet
übernommen und beim Speichern (ins PB-Format) wäre das es eh nicht
konvertiert worden.

Aber die Idee, ein bereits bestehendes Format (wie XAML) zu verwenden
(und kein neues Format zu erfinden), würde ich begrüssen.

Grüße ... Kiffi
a²+b²=mc²
Benutzeravatar
Leonhard
Beiträge: 602
Registriert: 01.03.2006 21:25

Beitrag von Leonhard »

milan1612 hat geschrieben:EDIT: Könntest du die Bugs die du gefunden hast mal kurz erläutern, dass
ich sie in meine Version mit einbauen kann?
Also irgendwo lag der Fehler in den DockLeft(...), DockRight(D...), Bottom(...), DockFill(...) - Befehlen. Wenn du die nochmal durchgehst oder bei meinem Code überprüfst, müsste dir da etwas auffallen. Ich hab im moment leider keine Zeit.

sory
Benutzeravatar
milan1612
Beiträge: 810
Registriert: 15.04.2007 17:58

Beitrag von milan1612 »

So, hab ganz vergessen das die 2. Version schon länger fertig ist.
Komplett neugeschrieben und (hoffentlich) ein bisschen schneller.
Das Grundkonzept bleibt das gleiche, allerdings ist die Bedienung jetzt etwas
komplizierter. Einfach mal das Beispiel anschauen oder die Include durchforsten.
Sollte einigermaßen gut kommentiert sein...

Die Include:

Code: Alles auswählen

;PureBasic Dock Include
;Second Edition
;Copyright 2008 - milan1612
;milan1612@gmx.de

EnableExplicit

;-== Public Interface ======================================
Enumeration
  #DockNone
  #DockLeft
  #DockRight
  #DockTop
  #DockBottom
  #DockFill
EndEnumeration

Structure Dock
  DockState.l  
  MarginLeft.l
  MarginRight.l
  MarginTop.l
  MarginBottom.l
  RedrawOnCall.l
  AntiFlicker.l
EndStructure

DeclareDLL SetGadgetDock(Gadget.l, *Options.Dock)
DeclareDLL IsGadgetDocked(Gadget.l)

;-== Implementation =========================================
;Internal Declarations
Declare UpdateDockInfo(Gadget.l, *Options.Dock)
Declare DockSubclassParent(Gadget.l)
Declare DockWindowCallback(WindowID.l, Message.l, wParam.l, lParam.l)
Declare FreeGadgetInfoCallback(GadgetID.l, UnUsed.l)
Declare CalculateClientArea(WindowID.l, *Rect.RECT)
Declare StatusToolBarEnumCallback(WindowID.l, Parent.l)
Declare DockGadgets(WindowID.l)
Declare DockEnumCallback(GadgetID.l, *Rect.RECT)

;Main Initialization Procedure (see Dock Structure above)
ProcedureDLL SetGadgetDock(Gadget.l, *Options.Dock)
  Protected *MemID.Dock
  If *Options
    If Not IsGadget(Gadget) : ProcedureReturn 0 : EndIf
    If IsGadgetDocked(Gadget)
      If *Options\DockState = #DockNone
        *MemID = GetProp_(GadgetID(Gadget), @"_DockInfo")
        If *MemID
          FreeMemory(*MemID)
          RemoveProp_(GadgetID(Gadget), @"_DockInfo")
        EndIf
      Else
        UpdateDockInfo(Gadget, *Options)
      EndIf
      ProcedureReturn 1
    EndIf
    *MemID = AllocateMemory(SizeOf(Dock))
    If *MemID
      DockSubclassParent(Gadget)
      CopyMemory(*Options, *MemID, SizeOf(Dock))
      SetProp_(GadgetID(Gadget), @"_DockInfo", *MemID)
      EnumChildWindows_(GetParent_(GadgetID(Gadget)), @StatusToolBarEnumCallback(), GetParent_(GadgetID(Gadget)))
      If *Options\RedrawOnCall
        SendMessage_(GetParent_(GadgetID(Gadget)), #WM_SIZE, 0, 0)
        InvalidateRect_(GetParent_(GadgetID(Gadget)), 0, 0)
      EndIf
      If Not GetWindowLong_(GetParent_(GadgetID(Gadget)), #GWL_STYLE) & #WS_CLIPCHILDREN
        SetWindowLong_(GetParent_(GadgetID(Gadget)), #GWL_STYLE, GetWindowLong_(GetParent_(GadgetID(Gadget)), #GWL_STYLE) | #WS_CLIPCHILDREN)
      EndIf
      If GadgetType(Gadget) = #PB_GadgetType_Frame3D
        If Not GetWindowLong_(GadgetID(Gadget), #GWL_EXSTYLE) & #WS_EX_TRANSPARENT
          SetWindowLong_(GadgetID(Gadget), #GWL_EXSTYLE, GetWindowLong_(GadgetID(Gadget), #GWL_EXSTYLE) | #WS_EX_TRANSPARENT)
        EndIf
      EndIf
      If GadgetType(Gadget) = #PB_GadgetType_Panel
        If Not GetWindowLong_(GadgetID(Gadget), #GWL_EXSTYLE) & #WS_EX_COMPOSITED
          SetWindowLong_(GadgetID(Gadget), #GWL_EXSTYLE, GetWindowLong_(GadgetID(Gadget), #GWL_EXSTYLE) | #WS_EX_COMPOSITED)
        EndIf
      EndIf
    EndIf
  Else
    ProcedureReturn 0
  EndIf
  ProcedureReturn 1
EndProcedure

;Checks if the gadget is docked, if true it returns the address to the stored dockinfo
ProcedureDLL IsGadgetDocked(Gadget.l)
  If IsGadget(Gadget)
    ProcedureReturn GetProp_(GadgetID(Gadget), @"_DockInfo")
  Else
    ProcedureReturn 0
  EndIf
EndProcedure

;-== Internals ==============================================

;Updates the stored dockinfo
Procedure UpdateDockInfo(Gadget.l, *Options.Dock)
  Protected *MemID.Dock
  *MemID = GetProp_(GadgetID(Gadget), @"_DockInfo")
  If *MemID
    CopyMemory(*Options, *MemID, SizeOf(Dock))
  EndIf
EndProcedure

;Subclasses (if necessary) the parent of the child
Procedure DockSubclassParent(Gadget.l)
  Protected ParentHandle.l
  Protected OldProc.l
  ParentHandle = GetParent_(GadgetID(Gadget))
  OldProc = GetProp_(ParentHandle, @"_OldProcAddress")
  If Not OldProc
    OldProc = SetWindowLong_(ParentHandle, #GWL_WNDPROC, @DockWindowCallback())
    SetProp_(ParentHandle, @"_OldProcAddress", OldProc) 
  EndIf
EndProcedure

;The gadgets parent callback
Procedure DockWindowCallback(WindowID.l, Message.l, wParam.l, lParam.l)
  Protected OldProc.l
  Protected Result.l
  Protected Buffer.s
  OldProc = GetProp_(WindowID, @"_OldProcAddress")
  Select Message
    Case #WM_DESTROY
      EnumChildWindows_(WindowID, @FreeGadgetInfoCallback(), 1)
    Case #WM_NCDESTROY
      RemoveProp_(WindowID, @"_OldProcAddress")
    Case #WM_SIZE
      DockGadgets(WindowID)
    Case #WM_PARENTNOTIFY
      If wParam & $FFFF = #WM_CREATE Or wParam & $FFFF = #WM_DESTROY
        Buffer = Space(100)
        If GetClassName_(lParam, @Buffer, 100)
          Buffer = LCase(Buffer)
          If Buffer = "toolbarwindow32"
            If wParam & $FFFF = #WM_CREATE
              SetProp_(WindowID, @"_ToolBarHandle", lParam)
            Else
              RemoveProp_(WindowID, @"_ToolBarHandle")
            EndIf
          ElseIf Buffer = "msctls_statusbar32"
            If wParam & $FFFF = #WM_CREATE
              SetProp_(WindowID, @"_StatusBarHandle", lParam)
            Else
              RemoveProp_(WindowID, @"_StatusBarHandle")
            EndIf
          EndIf
        EndIf
      EndIf
    Default
      Result = CallWindowProc_(OldProc, WindowID, Message, wParam, lParam)
  EndSelect
  ProcedureReturn Result
EndProcedure

;EnumChildWindows Callback to free the stored memory of the gadgets when destroyed
Procedure FreeGadgetInfoCallback(GadgetID.l, UnUsed.l)
  Protected *DockID.Dock
  *DockID = GetProp_(GadgetID, @"_DockInfo")
  If *DockID
    FreeMemory(*DockID)
    RemoveProp_(GadgetID, @"_DockInfo")
  EndIf
  ProcedureReturn 1
EndProcedure

;Calculates the rectangle that is then used to position the gadgets
Procedure CalculateClientArea(WindowID.l, *Rect.RECT)
  Protected StatusBar, ToolBar
  Protected TempRect.RECT
  GetClientRect_(WindowID, *Rect.RECT)
  StatusBar = GetProp_(WindowID, @"_StatusBarHandle")
  ToolBar = GetProp_(WindowID, @"_ToolBarHandle")
  If ToolBar
    GetWindowRect_(ToolBar, @TempRect)
    *Rect\top + (TempRect\bottom - TempRect\top) + 2
    SendMessage_(ToolBar, #WM_SIZE, 0, 0)
  EndIf
  If StatusBar
    GetWindowRect_(StatusBar, @TempRect)
    *Rect\bottom - (TempRect\bottom - TempRect\top)
    SendMessage_(StatusBar, #WM_SIZE, 0, 0)
  EndIf
EndProcedure

;EnumChildWindows Callback to find & identify possible status- and toolbars
Procedure StatusToolBarEnumCallback(WindowID.l, Parent.l)
  Protected Buffer.s = Space(100)
  If GetClassName_(WindowID, @Buffer, 100)
    Buffer = LCase(Buffer)
    If Buffer = "toolbarwindow32"
      SetProp_(Parent, @"_ToolBarHandle", WindowID)
    ElseIf Buffer = "msctls_statusbar32"
      SetProp_(Parent, @"_StatusBarHandle", WindowID)
    EndIf
  EndIf
  ProcedureReturn 1
EndProcedure

;Handles the entire dock process
Procedure DockGadgets(WindowID.l)
  Protected Rect.RECT
  LockWindowUpdate_(WindowID)
    CalculateClientArea(WindowID, @Rect)
    EnumChildWindows_(WindowID, @DockEnumCallback(), @Rect)
  LockWindowUpdate_(0)
  UpdateWindow_(WindowID)
EndProcedure

;EnumChildWindows Callback to dock the gadgets
;Warning: Enumerates Child-childs as well (todo)
Procedure DockEnumCallback(GadgetID.l, *Rect.RECT)
  Protected *Info.Dock
  Protected GadgetX, GadgetY, GadgetW, GadgetH
  Protected GadgetRect.RECT
  *Info = GetProp_(GadgetID, @"_DockInfo")
  If *Info
    GetWindowRect_(GadgetID, @GadgetRect)
    If *Info\AntiFlicker
      SendMessage_(GadgetID, #WM_SETREDRAW, 0, 0)
    EndIf
    Select *Info\DockState
      Case #DockLeft
        GadgetX = *Rect\left + *Info\MarginLeft
        GadgetY = *Rect\top + *Info\MarginTop
        GadgetW = GadgetRect\right - GadgetRect\left
        GadgetH = *Rect\bottom - *Rect\top - *Info\MarginTop - *Info\MarginBottom
        *Rect\left = *Rect\left + *Info\MarginLeft + (GadgetRect\right - GadgetRect\left) + *Info\MarginRight
      Case #DockRight
        GadgetX = (*Rect\right - (GadgetRect\right - GadgetRect\left)) - *Info\MarginRight
        GadgetY = *Rect\top + *Info\MarginTop
        GadgetW = GadgetRect\right - GadgetRect\left
        GadgetH = (*Rect\bottom - *Rect\top) - (*Info\MarginTop + *Info\MarginBottom)
        *Rect\right = *Rect\right - (*Info\MarginRight + *Info\MarginLeft) - (GadgetRect\right - GadgetRect\left)
      Case #DockTop
        GadgetX = *Rect\left + *Info\MarginLeft
        GadgetY = *Rect\top + *Info\MarginTop
        GadgetW = (*Rect\right - *Rect\left) - (*Info\MarginLeft + *Info\MarginRight)
        GadgetH = GadgetRect\bottom - GadgetRect\top
        *Rect\top = *Rect\top + *Info\MarginTop + (GadgetRect\bottom - GadgetRect\top) + *Info\MarginBottom
      Case #DockBottom
        GadgetX = *Rect\left + *Info\MarginLeft
        GadgetY = *Rect\bottom - (GadgetRect\bottom - GadgetRect\top) - *Info\MarginBottom
        GadgetW = *Rect\right - *Rect\left - *Info\MarginLeft - *Info\MarginRight
        GadgetH = (GadgetRect\bottom - GadgetRect\top)
        *Rect\bottom = *Rect\bottom - (*Info\MarginBottom + *Info\MarginTop + (GadgetRect\bottom - GadgetRect\top))
      Case #DockFill
        GadgetX = *Rect\left + *Info\MarginLeft
        GadgetY = *Rect\top + *Info\MarginTop
        GadgetW = *Rect\right - *Rect\left - *Info\MarginLeft - *Info\MarginRight
        GadgetH = *Rect\bottom - *Rect\top - *Info\MarginTop - *Info\MarginBottom
    EndSelect
    MoveWindow_(GadgetID, GadgetX, GadgetY, GadgetW, GadgetH, 1)
    If *Info\AntiFlicker
      SendMessage_(GadgetID, #WM_SIZE, 0, 0)
      SendMessage_(GadgetID, #WM_SETREDRAW, 1, 0)
      InvalidateRect_(GadgetID, 0, 0)
    EndIf
  EndIf
  ProcedureReturn 1
EndProcedure
Und ein kleines Beispiel:

Code: Alles auswählen

;IncludeFile "Dock.pb"

#Flags = #PB_Window_MaximizeGadget|#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered|#PB_Window_SizeGadget|#PB_Window_SystemMenu
OpenWindow(0, 0, 0, 630, 480, "Dock Example", #Flags)
CreateGadgetList(WindowID(0))

ButtonGadget(0, 0, 0, 80, 20, "Left")
ButtonGadget(1, 0, 0, 80, 20, "Right")
ButtonGadget(2, 0, 0, 80, 40, "Top")
ButtonGadget(3, 0, 0, 80, 40, "Bottom")
ButtonGadget(4, 0, 0, 80, 20, "Fill")

Define info.Dock
info\DockState = #DockLeft
info\MarginLeft = 2
info\MarginTop = 2
info\MarginBottom = 2
info\AntiFlicker = 1
SetGadgetDock(0, @info)

ZeroMemory_(@info, SizeOf(Dock))
info\DockState = #DockRight
info\MarginRight = 2
info\MarginTop = 2
info\MarginBottom = 2
info\AntiFlicker = 1
SetGadgetDock(1, @info)

ZeroMemory_(@info, SizeOf(Dock))
info\DockState = #DockTop
info\MarginLeft = 2
info\MarginRight = 2
info\MarginTop = 2
info\AntiFlicker = 1
SetGadgetDock(2, @info)

ZeroMemory_(@info, SizeOf(Dock))
info\DockState = #DockBottom
info\MarginLeft = 2
info\MarginRight = 2
info\MarginBottom = 2
info\AntiFlicker = 1
SetGadgetDock(3, @info)

ZeroMemory_(@info, SizeOf(Dock))
info\DockState = #DockFill
info\MarginLeft = 2
info\MarginRight = 2
info\MarginBottom = 2
info\MarginTop = 2
info\RedrawOnCall = 1
info\AntiFlicker = 1
SetGadgetDock(4, @info)

Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
Bitte nicht hauen falls was nicht funktionieren sollte (ist schon ne Weile her) :|
Bin nur noch sehr selten hier, bitte nur noch per PN kontaktieren
Benutzeravatar
Kiffi
Beiträge: 10714
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Beitrag von Kiffi »

milan1612 hat geschrieben:So, hab ganz vergessen das die 2. Version schon länger fertig ist.
da komme ich doch glatt mal mit meinem Code, den ich auch schon
beim letzten Test verwendet habe:

Code: Alles auswählen

TreeGadget    (1, 0, 0, 100,  40)
ListViewGadget(2, 0, 0,  80, 100)
EditorGadget  (3, 0, 0,  80,  50)
 
Define info.Dock
info\DockState = #DockLeft
info\MarginLeft = 2
info\MarginTop = 2
info\MarginBottom = 2
info\AntiFlicker = 1
SetGadgetDock(1, @info)

ZeroMemory_(@info, SizeOf(Dock))
info\DockState = #DockTop
info\MarginRight = 2
info\MarginTop = 2
info\MarginBottom = 2
info\AntiFlicker = 1
SetGadgetDock(2, @info)

ZeroMemory_(@info, SizeOf(Dock))
info\DockState = #DockFill
info\MarginLeft = 2
info\MarginRight = 2
info\MarginTop = 2
info\AntiFlicker = 1
SetGadgetDock(3, @info)
also, irgendwie sieht das ein wenig merkwürdig aus... ;-)

BTW: AntiFlicker = 1 -> Ich kann mir jetzt nicht vorstellen, dass das
jemand freiwillig auf 0 stellt. Ich würde es als Parameter rausnehmen und
generell mit AntiFlicker arbeiten ;-)

Grüße ... Kiffi
a²+b²=mc²
Benutzeravatar
milan1612
Beiträge: 810
Registriert: 15.04.2007 17:58

Beitrag von milan1612 »

Kiffi hat geschrieben: also, irgendwie sieht das ein wenig merkwürdig aus... ;-)
Ist ja auch logisch weil du RedrawOnCall bei deinem letzten Gadget vergessen hast :wink:
Dieses Flag hab ich eingebaut damit wenn man mehrere Gadgets "dockt" nicht bei
jedem Aufruf neu gezeichnet werden muss.
Kiffi hat geschrieben: BTW: AntiFlicker = 1 -> Ich kann mir jetzt nicht vorstellen, dass das
jemand freiwillig auf 0 stellt. Ich würde es als Parameter rausnehmen und
generell mit AntiFlicker arbeiten ;-)
Da es bei verschiedenen Gadgets noch Probleme mit dem Flackern gibt, lass ich
es erstmal noch drin, damit man notfalls selbst Hand anlegen kann...

Milan
Bin nur noch sehr selten hier, bitte nur noch per PN kontaktieren
Benutzeravatar
Kiffi
Beiträge: 10714
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Beitrag von Kiffi »

milan1612 hat geschrieben:Ist ja auch logisch weil du RedrawOnCall bei deinem letzten Gadget vergessen hast :wink:
ah, jetzt ja! Sorry, das hatte ich übersehen.

Danke für's Teilen! :allright:

Grüße ... Kiffi
a²+b²=mc²
Benutzeravatar
FGK
Beiträge: 249
Registriert: 09.01.2005 14:02
Computerausstattung: i5-4430 CPU / 8GB RAM
GeForce GT630
Windows 10 Home / 64-bit
Wohnort: Augsburg

Beitrag von FGK »

@milan1612

Geniale Sache dein Include :allright:

Aber, kann es sein daß Panelgadgets nicht richtig redrawed werden?
oder hab ich was falsch angegeben?

Code: Alles auswählen

IncludeFile "Dock.pb" 

#Flags = #PB_Window_MaximizeGadget|#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered|#PB_Window_SizeGadget|#PB_Window_SystemMenu 
OpenWindow(0, 0, 0, 630, 480, "Dock Example", #Flags) 
CreateGadgetList(WindowID(0)) 
  
TreeGadget    (1, 0, 0, 100,  40) 
ListViewGadget(2, 0, 0,  80, 100) 
ContainerGadget(4,0,0,300,50)
SetGadgetColor(4,#PB_Gadget_BackColor,RGB(0,255,100))
ButtonGadget  (3, 0, 0,  80,  25,"Hallo") 
CloseGadgetList()
ButtonGadget  (5, 0, 0,  80,  50,"Hallo 2") 
  
Define info.Dock 
info\DockState = #DockLeft 
info\MarginLeft = 2 
info\MarginTop = 2 
info\MarginBottom = 2 
info\AntiFlicker = 1 
SetGadgetDock(1, @info) 

ZeroMemory_(@info, SizeOf(Dock)) 
info\DockState = #DockTop 
info\MarginRight = 2 
info\MarginTop = 2 
info\MarginBottom = 2 
info\AntiFlicker = 1 
SetGadgetDock(2, @info) 

ZeroMemory_(@info, SizeOf(Dock)) 
info\DockState = #DockBottom 
info\MarginLeft = 10 
info\MarginRight = 10 
info\MarginTop = 10 
info\AntiFlicker = 1
info\RedrawOnCall = 1 
SetGadgetDock(4, @info)

ZeroMemory_(@info, SizeOf(Dock)) 
info\DockState = #DockRight 
info\MarginLeft = 2 
info\MarginRight = 2 
info\MarginTop = 2 
info\AntiFlicker = 1
SetGadgetDock(3, @info)

ZeroMemory_(@info, SizeOf(Dock)) 
info\DockState = #DockFill 
info\MarginLeft = 2 
info\MarginRight = 2 
info\MarginTop = 2 
info\AntiFlicker = 1
info\RedrawOnCall = 1 
SetGadgetDock(5, @info)


Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
Gruß FGK
Antworten