Dialogs, API/OOP style

Share your advanced PureBasic knowledge/code with the community.
Justin
Addict
Addict
Posts: 948
Joined: Sat Apr 26, 2003 2:49 pm

Dialogs, API/OOP style

Post by Justin »

Code updated For 5.20+

I created a kind of class(or object) to create dialogs in memory, functions are not commented but there is an example that covers all. I plan to do a propertysheet class that uses the dialog class, if there is some interest i'll post it.

All API, not for beginners you'll need to know about window styles, dialog procedure, etc.. but makes the task of creating the memory template very easy.

The example dialog with 2 controls compiles in 5kb, you will need to disable XP themes support when creating the exe, don't know if this is normal.

You can run the following code directly(object + example)

Code: Select all

;Dialogs using memory templates
;Justin 09/2004

;dialogs.pbi

Interface IDialog
  CreateTmpl(Style.l, ExStyle.l, x.w, y.w, w.w, h.w, title$, font$, pointSize.w)
  OpenModal(hwnd.l, dlgProc.l, param)
  AddControl(class$, Style.l, ExStyle.l, x.w, y.w, w.w, h.w, title$, id.w)
  DestroyTmpl()
  OpenModeless(hwnd.l, dlgProc.l, param)
  get_Tmpl()
EndInterface

Structure DialogFunctionsVT
  DLG_CreateTmpl.l
  DLG_OpenModal.l
  DLG_AddControl.l
  DLG_DestroyTmpl.l
  DLG_OpenModeless.l
  DLG_get_Tmpl.l
EndStructure

Structure DialogOBJ
  *VirtualTable.DialogFunctionsVT
  
  ;properties
  tmpl.l      ;memory template
  tmplSize.l
  cdit.w      ;nr. dlg items
EndStructure

;- DECLARATION
Declare DLG_CreateTmpl(*THIS.DialogOBJ, Style.l, ExStyle.l, x.w, y.w, w.w, h.w, title$, font$, pointSize.w)
Declare DLG_OpenModal(*THIS.DialogOBJ, hwnd.l, dlgProc.l, param)
Declare DLG_AddControl(*THIS.DialogOBJ, class$, Style.l, ExStyle.l, x.w, y.w, w.w, h.w, title$, id.w)
Declare DLG_DestroyTmpl(*THIS.DialogOBJ)
Declare DLG_OpenModeless(*THIS.DialogOBJ, hwnd.l, dlgProc.l, param)
Declare DLG_get_Tmpl(*THIS.DialogOBJ)
Declare CDialog(*THIS.DialogOBJ, *Idlg.LONG)

;- CONSTRUCTOR
Global g_DialogFunctionsVT.DialogFunctionsVT
g_DialogFunctionsVT\DLG_CreateTmpl = @DLG_CreateTmpl()
g_DialogFunctionsVT\DLG_OpenModal = @DLG_OpenModal()
g_DialogFunctionsVT\DLG_AddControl = @DLG_AddControl()
g_DialogFunctionsVT\DLG_OpenModeless = @DLG_OpenModeless()
g_DialogFunctionsVT\DLG_DestroyTmpl = @DLG_DestroyTmpl()
g_DialogFunctionsVT\DLG_get_Tmpl = @DLG_get_Tmpl()

;dialogs.pb
Procedure CDialog(*THIS.DialogOBJ, *Idlg.LONG)
  *THIS\VirtualTable = g_DialogFunctionsVT
  If *Idlg : *Idlg\l = *THIS : EndIf
EndProcedure

Procedure DLG_get_Tmpl(*THIS.DialogOBJ) : ProcedureReturn *THIS\tmpl : EndProcedure

Procedure DLG_DestroyTmpl(*THIS.DialogOBJ)
  If *THIS\tmpl : FreeMemory(*THIS\tmpl) : EndIf
EndProcedure

Procedure DLG_CreateTmpl(*THIS.DialogOBJ, Style.l, ExStyle.l, x.w, y.w, w.w, h.w, title$, font$, pointSize.w)
  *pwTemp.WORD
  
  *THIS\tmplSize = SizeOf(DLGTEMPLATE) + (SizeOf(WORD)*2) ;menu, class arrays
  *THIS\tmpl = AllocateMemory(*THIS\tmplSize)
  *dtmp.DLGTEMPLATE = *THIS\tmpl
  *dtmp\style = Style
  *dtmp\dwExtendedStyle = dwExtendedStyle
  *dtmp\cdit = 0
  *dtmp\x = x
  *dtmp\y = y
  *dtmp\cx = w
  *dtmp\cy = h
  
  ;title array
  arrLen = 0
  If title$=""
    arrLen = SizeOf(WORD)
    *THIS\tmplSize + arrLen
    *THIS\tmpl = ReAllocateMemory(*THIS\tmpl, *THIS\tmplSize)
  Else
    wLen = MultiByteToWideChar_(#CP_ACP, 0, title$, -1, 0, 0)*2
    arrLen + wLen
    
    *THIS\tmplSize + arrLen
    *THIS\tmpl = ReAllocateMemory(*THIS\tmpl, *THIS\tmplSize)
    ;set title
    MultiByteToWideChar_(#CP_ACP, 0, title$, -1, *dtmp + *THIS\tmplSize - arrLen, wLen)
  EndIf
  
  ;font array
  If font$
    arrLen = SizeOf(WORD) ;point size
    
    wLen = MultiByteToWideChar_(#CP_ACP, 0, font$, -1, 0, 0)*2
    arrLen  + wLen
    
    *THIS\tmplSize + arrLen
    *THIS\tmpl = ReAllocateMemory(*THIS\tmpl, *THIS\tmplSize)   
    ;set pointsize
    *pwTemp = *dtmp + *THIS\tmplSize - arrLen : *pwTemp\w = pointSize
    ;set font name
    MultiByteToWideChar_(#CP_ACP, 0, font$, -1, *pwTemp + SizeOf(WORD), wLen)
  EndIf
  
  *THIS\tmplSize + (*THIS\tmplSize % 4)
  *THIS\tmpl = ReAllocateMemory(*THIS\tmpl, *THIS\tmplSize)   
EndProcedure

Procedure DLG_OpenModal(*THIS.DialogOBJ, hwnd.l, dlgProc.l, param)
  ProcedureReturn DialogBoxIndirectParam_(GetModuleHandle_(0), *THIS\tmpl, hwnd, dlgProc, param)
EndProcedure

Procedure DLG_OpenModeless(*THIS.DialogOBJ, hwnd.l, dlgProc.l, param)
  ProcedureReturn CreateDialogIndirectParam_(GetModuleHandle_(0), *THIS\tmpl, hwnd, dlgProc, param)
EndProcedure

Procedure DLG_AddControl(*THIS.DialogOBJ, class$, Style.l, ExStyle.l, x.w, y.w, w.w, h.w, title$, id.w)   
  If class$="" Or *THIS\tmpl=0 : ProcedureReturn 0 : EndIf ;error
  
  *THIS\tmplSize + SizeOf(DLGITEMTEMPLATE)
  *THIS\tmpl = ReAllocateMemory(*THIS\tmpl, *THIS\tmplSize)
  
  *dit.DLGITEMTEMPLATE = *THIS\tmpl + *THIS\tmplSize - SizeOf(DLGITEMTEMPLATE)
  *dit\style = Style
  *dit\dwExtendedStyle = ExStyle
  *dit\x = x
  *dit\y = y
  *dit\cx = w
  *dit\cy = h
  *dit\id = id
  
  itemLen = SizeOf(DLGITEMTEMPLATE)
  
  ;class array
  arrLen = 0
  wLen = MultiByteToWideChar_(#CP_ACP, 0, class$, -1, 0, 0)*2
  arrLen + wLen
  itemLen + arrLen
  
  *THIS\tmplSize + arrLen
  *THIS\tmpl = ReAllocateMemory(*THIS\tmpl, *THIS\tmplSize)   
  ;set class
  MultiByteToWideChar_(#CP_ACP, 0, class$, -1, *THIS\tmpl + *THIS\tmplSize - arrLen, wlen)
  
  ;title array
  If title$
    arrLen = 0
    wLen = MultiByteToWideChar_(#CP_ACP, 0, title$, -1, 0, 0)*2
    arrLen + wLen
    itemLen + arrLen
    
    *THIS\tmplSize + arrLen
    *THIS\tmpl = ReAllocateMemory(*THIS\tmpl, *THIS\tmplSize)   
    ;set title
    MultiByteToWideChar_(#CP_ACP, 0, title$, -1, *THIS\tmpl + *THIS\tmplSize - arrLen, wlen)
  Else
    arrLen = SizeOf(WORD)
    itemLen + arrLen
    *THIS\tmplSize + arrLen
    *THIS\tmpl = ReAllocateMemory(*THIS\tmpl, *THIS\tmplSize)         
  EndIf
  
  ;creation data array
  arrLen = SizeOf(WORD)
  itemLen + arrLen
  *THIS\tmplSize + arrLen
  *THIS\tmpl = ReAllocateMemory(*THIS\tmpl, *THIS\tmplSize)   
  
  *THIS\tmplSize + (itemLen % 4)
  *THIS\tmpl = ReAllocateMemory(*THIS\tmpl, *THIS\tmplSize)
  
  *THIS\cdit + 1
  *dtmp.DLGTEMPLATE = *THIS\tmpl
  *dtmp\cdit = *THIS\cdit
  ProcedureReturn *THIS\cdit
EndProcedure

;dialogs_test.pb
;- TEST
Enumeration
  #IDC_BT
  #IDC_ED
EndEnumeration

Procedure DlgProc1(hwnd, msg, wParam, lParam)
  Select msg
    Case #WM_COMMAND
      Select wparam>>16
        Case #BN_CLICKED
          Select wparam & $ffff
            Case #IDC_BT
              Debug "click"
              
          EndSelect
      EndSelect
      ProcedureReturn 1
      
    Case #WM_CLOSE
      EndDialog_(hwnd, 1)
      ProcedureReturn 1
      
    Default : ProcedureReturn 0
  EndSelect
EndProcedure

;create dialog
CDialog(@oDLG1.DialogOBJ, @pDLG1.IDialog)
pDLG1\CreateTmpl(#WS_SYSMENU|#DS_SETFONT, 0, 10, 10, 200, 200, "Modal Dialog", "Arial", 10)
pDLG1\AddControl("Button", #WS_VISIBLE|#WS_CHILD, 0, 2, 2, 80, 20, "Click Me", #IDC_BT)
pDLG1\AddControl("Edit", #WS_VISIBLE|#WS_CHILD, #WS_EX_CLIENTEDGE, 0, 40, 40, 20, "text", #IDC_ED)

;open
pDLG1\OpenModal(0, @DlgProc1(), 0)

;free memory template
pDLG1\DestroyTmpl()
End
Moonshine
Enthusiast
Enthusiast
Posts: 263
Joined: Tue May 25, 2004 12:13 am
Location: UK

Post by Moonshine »

Runs fine here, very interesting. Have to have a closer look in a bit.
Mark my words, when you least expect it, your uppance will come...
Justin
Addict
Addict
Posts: 948
Joined: Sat Apr 26, 2003 2:49 pm

Post by Justin »

Thinking about size, the object could be used just in a separate file outside the main program to create the dialogs, then add a function to save the dialog template as a binary file and using it as an include in the main program, you could open the dialog in a single api call like if it were a resource template.
User avatar
GedB
Addict
Addict
Posts: 1313
Joined: Fri May 16, 2003 3:47 pm
Location: England
Contact:

Post by GedB »

Very nice. :D
PolyVector
Enthusiast
Enthusiast
Posts: 499
Joined: Wed Sep 17, 2003 9:17 pm
Location: Southern California
Contact:

Post by PolyVector »

NICE! This will be very usefull for future projects.... now all we need is a way to easily grab a dialog from a resource :)
Justin
Addict
Addict
Posts: 948
Joined: Sat Apr 26, 2003 2:49 pm

Post by Justin »

now all we need is a way to easily grab a dialog from a resource
from the PB exe?, the only methods are the one i mentioned, it does not convince me because you have to mantain 2 files, or create a parser that reads an ascii file from inside the exe and builds a memory template from that, i'm not sure if it will be beaten the purpose of the memory template.

about the code, the line in DLG_CreateTmpl()

;set pointsize
*pwTemp = *dtmp + *THIS\tmplSize - arrLen : *pwTemp\w = pointSize

should be

;set pointsize
*pwTemp = *THIS\tmpl + *THIS\tmplSize - arrLen : *pwTemp\w = pointSize

assuming that reallocatememory() changes the returned handle in every call, but strangly it works as is now

the complete function with the change:
Procedure DLG_CreateTmpl(*THIS.DialogOBJ, Style.l, ExStyle.l, x.w, y.w, w.w, h.w, title$, font$, pointSize.w)
*pwTemp.WORD

*THIS\tmplSize = SizeOf(DLGTEMPLATE) + (SizeOf(WORD)*2) ;menu, class arrays
*THIS\tmpl = AllocateMemory(*THIS\tmplSize)
*dtmp.DLGTEMPLATE = *THIS\tmpl
*dtmp\style = Style
*dtmp\dwExtendedStyle = dwExtendedStyle
*dtmp\cdit = 0
*dtmp\x = x
*dtmp\y = y
*dtmp\lx = w
*dtmp\ly = h

;title array
arrLen = 0
If title$=""
arrLen = SizeOf(WORD)
*THIS\tmplSize + arrLen
*THIS\tmpl = ReAllocateMemory(*THIS\tmpl, *THIS\tmplSize)
Else
wLen = MultiByteToWideChar_(#CP_ACP, 0, title$, -1, 0, 0)*2
arrLen + wLen

*THIS\tmplSize + arrLen
*THIS\tmpl = ReAllocateMemory(*THIS\tmpl, *THIS\tmplSize)
;set title
MultiByteToWideChar_(#CP_ACP, 0, title$, -1, *dtmp + *THIS\tmplSize - arrLen, wLen)
EndIf

;font array
If font$
arrLen = SizeOf(WORD) ;point size

wLen = MultiByteToWideChar_(#CP_ACP, 0, font$, -1, 0, 0)*2
arrLen + wLen

*THIS\tmplSize + arrLen
*THIS\tmpl = ReAllocateMemory(*THIS\tmpl, *THIS\tmplSize)
;set pointsize
*pwTemp = *THIS\tmpl + *THIS\tmplSize - arrLen : *pwTemp\w = pointSize
;set font name
MultiByteToWideChar_(#CP_ACP, 0, font$, -1, *pwTemp + SizeOf(WORD), wLen)
EndIf

*THIS\tmplSize + (*THIS\tmplSize % 4)
*THIS\tmpl = ReAllocateMemory(*THIS\tmpl, *THIS\tmplSize)
EndProcedure
and if you try a modeless dialog you have to use the #WS_VISIBLE style, because they are hidden by default
Fred
Administrator
Administrator
Posts: 18253
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Post by Fred »

Nice example
Post Reply