Code : Tout sélectionner
;
; HIERARCHICAL POP-UP COMBO GADGET
; By Zapman with the help of TomS, Demivec and Nico
;
; This code allows to create a ComboGadget with hierarchical levels
;
; The resulting gadget has the same apparence as a ComboGadget but
; the same possibilities of a popupmenu and offers multiple levels
; in the data ordering as submenus.
;
; --------------------------
;
; Ce code permet de créer un ComboGadget avec des niveaux hiérarchiques
;
; Le résultat a la même apparence qu'un combogadget et les mêmes
; possibilités qu'un popupmenu puisqu'il permet de classer les données
; sur plusieurs niveaux dans des sous-menus.
;
; --------------------------
;
; ------------------------------------------------------
; Prepare a small Folder Icon to add to submenus
; ------------------------------------------------------
;
; Get the Folder Icon from Windows API
*sfi.SHFILEINFO = AllocateMemory(SizeOf(SHFILEINFO))
If SHGetFileInfo_("aa.txt",#FILE_ATTRIBUTE_DIRECTORY,*sfi, SizeOf(SHFILEINFO), #SHGFI_ICON| #SHGFI_SMALLICON | #SHGFI_USEFILEATTRIBUTES)
hFolderIcon = *sfi\hIcon
EndIf
FreeMemory(*sfi)
;
; Redraw the icon in an image
FImage = CreateImage(#PB_Any, 16, 16)
himg = StartDrawing(ImageOutput(FImage))
; --> White background to match menu background
Box(0, 0, 16, 16, RGB(255, 255, 255))
; --> Draw the icon
DrawImage(hFolderIcon, 0, 0, 16, 16)
DestroyIcon_(hFolderIcon)
StopDrawing()
;
; Resize the image to the menu needs
menuImageWidth = GetSystemMetrics_(#SM_CXMENUCHECK)
menuImageHeight = GetSystemMetrics_(#SM_CYMENUCHECK)
itemImage = ResizeImage(FImage, menuImageWidth, menuImageHeight)
;
; Set a MenuItemInfo Structure with our icon/image
Global myMenuInfo.MENUITEMINFO
myMenuInfo\cbSize = SizeOf(MENUITEMINFO)
myMenuInfo\fMask = #MIIM_CHECKMARKS
myMenuInfo\hbmpUnchecked = itemImage
;
Procedure SetSubMenuIcon(menu) ; add the folder icon to all submenus titles
mc = GetMenuItemCount_(menu)
For ct = 0 To mc
hSubMenu = GetSubMenu_(menu, ct) ; is the item a submenu title?
If hSubMenu ; if yes....
SetMenuItemInfo_(menu, ct, 1, myMenuInfo) ; add an icon
SetSubMenuIcon(hSubMenu) ; and explore the submenu for next levels
EndIf
Next
EndProcedure
;
; ------------------------------------------------------
; Define functions for our new gadget
; ------------------------------------------------------
;
Import ""
PB_Menu_SendMenuCommand(hWnd, EventType)
PB_Gadget_SendGadgetCommand(hWnd, EventType)
EndImport
;
#TPM_RETURNCMD=$100
;
Structure CBM
iGadgetID.i
iMenuID.i
iMenuOpen.i
iOldCBMCallBack.i
EndStructure
Global NewList hCBM.CBM()
Procedure CBMCallback(hWnd, uMsg, wParam, lParam)
;By Zapman with the help of TomS and Nico
;
If IsGadget(hCBM()\iGadgetID)
If hWnd <> GadgetID(hCBM()\iGadgetID)
ResetList(hCBM())
While NextElement(hCBM()) And hWnd <> GadgetID(hCBM()\iGadgetID) : Wend
EndIf
*PCBM.CBM = @hCBM()
If hWnd = GadgetID(*PCBM\iGadgetID)
If uMsg = #WM_LBUTTONDOWN Or uMsg = #WM_LBUTTONDBLCLK
If *PCBM\iMenuOpen=0
*PCBM\iMenuOpen = -1
SetFocus_(hwnd)
;
*PCBM\iMenuID = CreatePopupMenu(#PB_Any)
If *PCBM\iMenuID
For ct = 0 To CountGadgetItems(*PCBM\iGadgetID)-1
mline$ = GetGadgetItemText(*PCBM\iGadgetID,ct)
Open = 0
Close = 0
Value = SendMessage_(GadgetID(*PCBM\iGadgetID),#CB_GETITEMDATA,ct,0)
If Value<>#CB_ERR
Open = Value&1
Close = Value/2
EndIf
If Open
OpenSubMenu(mline$)
Else
MenuItem(ct+10000,mline$) ; we use menu items over 10000 to avoid conflicts with other application menus
EndIf
While Close
CloseSubMenu()
Close - 1
Wend
Next
;
; Transmit the event to the main application
;
PB_Gadget_SendGadgetCommand(GadgetID(*PCBM\iGadgetID),#CBN_DROPDOWN)
;
*PCBM\iMenuOpen = 1
;
EndIf
EndIf
ProcedureReturn 0 ; hide the event to the combogadget
;
ElseIf (uMsg = #WM_SETFOCUS Or uMsg = #WM_KILLFOCUS) And *PCBM\iMenuOpen = -1
; Avoid the EventType "SetFocus" on a mouse click
; because a classical ComboBox gadget does'nt send this event.
ProcedureReturn 0
;
ElseIf *PCBM\iMenuOpen = 1 And uMSG = #WM_NCHITTEST
*PCBM\iMenuOpen = 2
;
; Display the popup menu
GetWindowRect_(hWnd,re.RECT)
id=TrackPopupMenu_(MenuID(*PCBM\iMenuID),#TPM_RETURNCMD | #TPM_LEFTBUTTON | #TPM_LEFTALIGN ,re\left,re\bottom,0,GadgetID(*PCBM\iGadgetID),0)
If PeekMessage_(@msg.msg,hwnd,#WM_LBUTTONDOWN,#WM_LBUTTONDOWN,#PM_NOREMOVE)=0
; menu has been closed!
FreeMenu(*PCBM\iMenuID)
EndIf
;
; Menu is now closed. Update our combo with the menu choice,
; and generate a PB event to tell the main application that something occured
;
If id>0
SetGadgetState(*PCBM\iGadgetID,id-10000) ; Update our combo with the menu choice
PB_Gadget_SendGadgetCommand(GadgetID(*PCBM\iGadgetID), #CBN_SELCHANGE) ; Generate a PB event
Else
PB_Gadget_SendGadgetCommand(GadgetID(*PCBM\iGadgetID), #CBN_CLOSEUP) ; Generate a PB event
EndIf
;
ElseIf *PCBM\iMenuOpen = 2; the menu has just been displayed. Set the submenus icons
*PCBM\iMenuOpen = 0
SetSubMenuIcon(MenuID(*PCBM\iMenuID))
EndIf
;
ProcedureReturn CallWindowProc_(*PCBM\iOldCBMCallBack, hwnd, uMsg, wParam, lParam)
;
EndIf
EndIf
ProcedureReturn DefWindowProc_(hWnd, uMsg, wParam, lParam)
EndProcedure
Procedure CreateComboBoxMenuGadget(ID.i, iX.i, iY.i, iWidth.i, iHeight.i,Option=0)
;
ReturnValue = ComboBoxGadget(ID, iX, iY, iWidth, iHeight,Option)
AddElement(hCBM())
If ID = #PB_Any
hCBM()\iGadgetID = ReturnValue
Else
hCBM()\iGadgetID = ID
EndIf
hCBM()\iMenuOpen = 0
hCBM()\iOldCBMCallBack=SetWindowLong_(GadgetID(hCBM()\iGadgetID), #GWL_WNDPROC, @CBMCallBack())
ProcedureReturn ReturnValue
EndProcedure
;
Procedure OpenSubMenu_CBM(iGadgetID,ItemIndex=-1,Text$="_NoText_")
;
; Last two arguments are optionnals
;
; OpenSubMenu_CBM(GadgetID,-1,"Line")
; Add the line "Line" in the List As a submenu title
; OpenSubMenu_CBM(GadgetID)
; Transform the last added line To a submenu title
; OpenSubMenu_CBM(GadgetID,5)
; Transform the line indexed "5" To a submenu title
; OpenSubMenu_CBM(GadgetID,5,"Line")
; Insert "Line" at position "5" in the List And transform it To a submenu title
;
If Text$<>"_NoText_"
AddGadgetItem(iGadgetID, ItemIndex,Text$)
EndIf
;
If ItemIndex = -1
ItemIndex = CountGadgetItems(iGadgetID)-1
EndIf
;
vReturn = 0
actualValue = SendMessage_(GadgetID(iGadgetID),#CB_GETITEMDATA,ItemIndex,0)
If actualValue<>#CB_ERR
actualValue|1
If SendMessage_(GadgetID(iGadgetID),#CB_SETITEMDATA,ItemIndex,actualValue)<>#CB_ERR
vReturn = 1
EndIf
EndIf
ProcedureReturn vReturn
EndProcedure
;
Procedure CloseSubMenu_CBM(iGadgetID,ItemIndex=-1,Text$="_NoText_")
;
If Text$<>"_NoText_"
AddGadgetItem(iGadgetID, ItemIndex,Text$)
EndIf
;
If ItemIndex = -1
ItemIndex = CountGadgetItems(iGadgetID)-1
EndIf
;
vReturn = 0
actualValue = SendMessage_(GadgetID(iGadgetID),#CB_GETITEMDATA,ItemIndex,0)
If actualValue<>#CB_ERR
Open = actualValue&1
Close = actualValue/2
Close + 1
Close *2
Value = Close | Open
If SendMessage_(GadgetID(iGadgetID),#CB_SETITEMDATA,ItemIndex,Value)<>#CB_ERR
vReturn = 1
EndIf
EndIf
ProcedureReturn vReturn
EndProcedure
;
; ------------------------------------------------------
; DEMO CODE
; ------------------------------------------------------
mhWnd = OpenWindow(#PB_Any, 0,0, 480, 100, "Combobox", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
TextGadget(#PB_Any,10,5,140,20,"Classical ComboBox")
combomenu1 = ComboBoxGadget(#PB_Any,10, 25, 140, 20)
;
AddGadgetItem(combomenu1, -1,"Spaghetti")
AddGadgetItem(combomenu1, -1,"Great sole")
AddGadgetItem(combomenu1, -1,"Potato omelette")
AddGadgetItem(combomenu1, -1,"Fondue chinoise")
AddGadgetItem(combomenu1, -1,"Tapioca soup")
AddGadgetItem(combomenu1, -1,"Duck liver")
AddGadgetItem(combomenu1, -1,"Sauces")
AddGadgetItem(combomenu1, -1,"Chili")
AddGadgetItem(combomenu1, -1,"American")
AddGadgetItem(combomenu1, -1,"Indian")
AddGadgetItem(combomenu1, -1,"Kebap")
SetGadgetState(combomenu1, 2)
TextGadget(#PB_Any,170,5,140,20,"Hierarchical ComboBox")
combomenu2 = CreateComboBoxMenuGadget(#PB_Any,170, 25, 140, 20)
;
AddGadgetItem(combomenu2, -1,"Spaghetti")
AddGadgetItem(combomenu2, -1,"Great sole")
AddGadgetItem(combomenu2, -1,"Potato omelette")
AddGadgetItem(combomenu2, -1,"Fondue chinoise")
AddGadgetItem(combomenu2, -1,"Tapioca soup")
AddGadgetItem(combomenu2, -1,"Duck liver")
OpenSubMenu_CBM(combomenu2,-1,"Sauces") ; will open a submenu with the last added item as title
AddGadgetItem(combomenu2, -1,"Chili")
AddGadgetItem(combomenu2, -1,"American")
CloseSubMenu_CBM(combomenu2,-1,"Indian") ; will close the submenu
AddGadgetItem(combomenu2, -1,"Kebap")
SetGadgetState(combomenu2, 1)
TextGadget(#PB_Any,330,5,140,20,"Hierarchical ComboBox")
combomenu3 = CreateComboBoxMenuGadget(#PB_Any,330, 25, 140, 20)
;
AddGadgetItem(combomenu3, -1,"Spaghetti")
AddGadgetItem(combomenu3, -1,"Great sole")
AddGadgetItem(combomenu3, -1,"Potato omelette")
AddGadgetItem(combomenu3, -1,"Fondue chinoise")
AddGadgetItem(combomenu3, -1,"Tapioca soup")
AddGadgetItem(combomenu3, -1,"Duck liver")
AddGadgetItem(combomenu3, -1,"Sauces")
OpenSubMenu_CBM(combomenu3) ; will open a submenu with the last added item as title
AddGadgetItem(combomenu3, -1,"Chili")
AddGadgetItem(combomenu3, -1,"American")
AddGadgetItem(combomenu3, -1,"Indian")
CloseSubMenu_CBM(combomenu3) ; will close the submenu
AddGadgetItem(combomenu3, -1,"Kebap")
SetGadgetState(combomenu3, 0)
Repeat
event = WaitWindowEvent(20)
Select event
Case #PB_Event_Gadget
If EventGadget() = combomenu1
Debug "Event on the Classical Combo! GadgetState ="+Str(GetGadgetState(combomenu1))+" Selected line = "+GetGadgetText(combomenu1)+" EventType() = "+Str(EventType())
EndIf
If EventGadget() = combomenu2
Debug "Event on the Hierarchical Combo! GadgetState ="+Str(GetGadgetState(combomenu2))+" Selected line = "+GetGadgetText(combomenu2)+" EventType() = "+Str(EventType())
EndIf
EndSelect
Until event = #PB_Event_CloseWindow
CloseWindow(mhWnd)
End