Code: Select all
;- TOP
;.-------------------------------------------------------------------------------------------------
;|
;| Title : Module TabKey
;| Version : v1.0
;| Author : Mesa
;| Copyright :
;|
;| PureBasic : 5.70+ 6.0+
;|
;| Operating System : Windows (XP to W11+), Linux ?, MacOS ?
;| Processor : x86, x64
;|
;| API : Yes api used: Windows, MacOS and Linux
;|
;|-------------------------------------------------------------------------------------------------
;|
;| Description : Module to use the tabulation key with all gadgets
;|
;| Forum Topic : https://www.purebasic.fr/french/viewtopic.php?t=18938
;| https://www.purebasic.fr/english/viewtopic.php?t=81278
;| Website :
;|
;| Documentation :
;|
;| Date : 03/2023
;|
;| Misc. : Several procedures system from mk-soft: https://www.purebasic.fr/english/viewtopic.php?f=12&t=72980
;| Several procedures from Thorsten1867: MetaModule.pbi
;|
;|
;.-------------------------------------------------------------------------------------------------
;.-------------------------------------------------------------------------------------------------
;|
;| How to use : 1) Add or include the module
;| : 2) Add "UseModule TabKey" or use TabKey:: prefix
;| : 3) Choice 1: Add once "UseTabKey()" to manage all gadgets in all windows
;| Choice 2: Add "UseTabKey(WinID)" to manage all gadgets in the specified window
;| Choice 3: Add "AddTabKeyGadget(GadgetID)" to manage gadgets one by one ...
;|
;| : RemoveTabKeyGadget(GadgetID.i, RestoreInternalTab.i=#False)
;| : -> RestoreInternalTab.i=#False: Remove a gadget of the list
;| -> RestoreInternalTab.i=#True : The gadget restore its own tab (editorgadget,...)
;|
;.-------------------------------------------------------------------------------------------------
;.-------------------------------------------------------------------------------------------------
;|
;| Procedures
;| UseTabKey(WindowID.i=#PB_Default): Automatic management
;| AddTabKeyGadget(GadgetID.i, Flags.i=#False, WindowID.i=#PB_Default): Manual management
;| AddTabKeyWindow(WindowID.i): Manual management
;| RemoveTabKeyGadget(GadgetID.i, RestoreInternalTab.i=#False): Remove
;| DebugMe(): Debug
;|
;.-------------------------------------------------------------------------------------------------
;.-------------------------------------------------------------------------------------------------
;|
;| License Mesa.
;| The license Mesa is, do what you like but make the World better, easier and enjoyable.
;|
;|
;|
;| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
;| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
;| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
;| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
;| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
;| SOFTWARE.
;|
;.-------------------------------------------------------------------------------------------------
CompilerIf #PB_Compiler_IsMainFile
EnableExplicit
CompilerEndIf
;- ----------------------------------------------------------------------------
;- DeclareModule
;- ..................
DeclareModule TabKey
;- Constantes
#Enable_TabulationKey = #True
EnumerationBinary Option
#InternalTabKey ;=1
EndEnumeration
; Menu Events
#Event_TabKey = 64000
#Event_ShiftTabKey = 63999
;- Public Procedures
Declare.i AddTabKeyGadget(GadgetID.i, Flags.i=#False, WindowID.i=#PB_Default)
Declare.i AddTabKeyWindow(WindowID.i)
Declare.i UseTabKey(WindowID.i=#PB_Default)
Declare.i RemoveTabKeyGadget(GadgetID.i, RestoreInternalTab.i=#False)
; Declare.i DebugMe()
EndDeclareModule
;- ----------------------------------------------------------------------------
;- Module
;- ..................
;Mesa, mk-soft and Thorsten1867
Module TabKey
EnableExplicit
;- Structures
Structure TabKey_Gadget_Structure
Window.i
Flags.i
EndStructure
Structure TabKey_Window_Structure
List Gadget.i()
EndStructure
Structure TabKey_Structure
Menu.i
Map Window.TabKey_Window_Structure()
Map Gadget.TabKey_Gadget_Structure()
EndStructure
;- Global
Global TabKey.TabKey_Structure
;- Private Procedures
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
Import ""
PB_Object_EnumerateStart(PB_Objects)
PB_Object_EnumerateNext(PB_Objects, *ID.Integer)
PB_Object_EnumerateAbort(PB_Objects)
PB_Window_Objects
PB_Gadget_Objects
EndImport
CompilerElse
ImportC ""
PB_Object_EnumerateStart(PB_Objects)
PB_Object_EnumerateNext(PB_Objects, *ID.Integer)
PB_Object_EnumerateAbort(PB_Objects)
PB_Window_Objects.i
PB_Gadget_Objects.i
EndImport
CompilerEndIf
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
; PB Internal Structure Gadget MacOS
Structure sdkGadget
*gadget
*container
*vt
UserData.i
Window.i
Type.i
Flags.i
EndStructure
CompilerEndIf
Procedure WindowPB(WindowID)
Protected result, window
result = -1
PB_Object_EnumerateStart(PB_Window_Objects)
While PB_Object_EnumerateNext(PB_Window_Objects, @window)
If WindowID = WindowID(window)
result = window
Break
EndIf
Wend
PB_Object_EnumerateAbort(PB_Window_Objects)
ProcedureReturn result
EndProcedure
Procedure GetParentWindowID(Gadget)
Protected WindowID
If IsGadget(Gadget)
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_MacOS
Protected *Gadget.sdkGadget = IsGadget(Gadget)
WindowID = WindowID(*Gadget\Window)
CompilerCase #PB_OS_Linux
WindowID = gtk_widget_get_toplevel_(GadgetID(Gadget))
CompilerCase #PB_OS_Windows
WindowID = GetAncestor_(GadgetID(Gadget), #GA_ROOT)
CompilerEndSelect
EndIf
ProcedureReturn WindowID
EndProcedure
Procedure GetWindowID(Gadget)
ProcedureReturn WindowPB(GetParentWindowID(Gadget))
EndProcedure
Procedure GetWindowList(List Windows())
Protected object
ClearList(Windows())
PB_Object_EnumerateStart(PB_Window_Objects)
While PB_Object_EnumerateNext(PB_Window_Objects, @object)
AddElement(Windows())
Windows() = object
Wend
ProcedureReturn ListSize(Windows())
EndProcedure
Procedure GetGadgetList(List Gadgets(), WindowID=0)
Protected object
ClearList(Gadgets())
PB_Object_EnumerateStart(PB_Gadget_Objects)
If WindowID = 0
While PB_Object_EnumerateNext(PB_Gadget_Objects, @object)
AddElement(Gadgets())
Gadgets() = object
Wend
Else
While PB_Object_EnumerateNext(PB_Gadget_Objects, @object)
If GetParentWindowID(object) = WindowID
AddElement(Gadgets())
Gadgets() = object
EndIf
Wend
EndIf
ProcedureReturn ListSize(Gadgets())
EndProcedure
CompilerIf #Enable_TabulationKey
Procedure Event_Tab()
Protected Window
Window = GetActiveWindow()
If IsWindow(Window)
If FindMapElement(TabKey\Window(), Str(Window))
If NextElement(TabKey\Window()\Gadget())
If IsGadget(TabKey\Window()\Gadget())
SetActiveGadget(TabKey\Window()\Gadget())
EndIf
Else
FirstElement(TabKey\Window()\Gadget())
If IsGadget(TabKey\Window()\Gadget())
SetActiveGadget(TabKey\Window()\Gadget())
EndIf
EndIf
EndIf
EndIf
EndProcedure
Procedure Event_ShiftTab()
Protected Window
Window = GetActiveWindow()
If IsWindow(Window)
If FindMapElement(TabKey\Window(), Str(Window))
If PreviousElement(TabKey\Window()\Gadget())
If IsGadget(TabKey\Window()\Gadget()) : SetActiveGadget(TabKey\Window()\Gadget()) : EndIf
Else
LastElement(TabKey\Window()\Gadget())
If IsGadget(TabKey\Window()\Gadget()) : SetActiveGadget(TabKey\Window()\Gadget()) : EndIf
EndIf
EndIf
EndIf
EndProcedure
Procedure Event_Focus()
Protected GadgetID = EventGadget()
If FindMapElement(TabKey\Gadget(), Str(GadgetID))
If TabKey\Gadget()\Flags & #InternalTabKey
If IsMenu(TabKey\Menu)
UnbindMenuEvent(TabKey\Menu, #Event_TabKey, @Event_Tab())
UnbindMenuEvent(TabKey\Menu, #Event_ShiftTabKey, @Event_ShiftTab())
EndIf
If IsWindow(TabKey\Gadget()\Window)
RemoveKeyboardShortcut(TabKey\Gadget()\Window, #PB_Shortcut_Tab)
RemoveKeyboardShortcut(TabKey\Gadget()\Window, #PB_Shortcut_Shift|#PB_Shortcut_Tab)
EndIf
EndIf
EndIf
EndProcedure
Procedure Event_LostFocus()
Protected GadgetID = EventGadget()
If FindMapElement(TabKey\Gadget(), Str(GadgetID))
If TabKey\Gadget()\Flags & #InternalTabKey
If IsWindow(TabKey\Gadget()\Window)
AddKeyboardShortcut(TabKey\Gadget()\Window, #PB_Shortcut_Tab, #Event_TabKey)
AddKeyboardShortcut(TabKey\Gadget()\Window, #PB_Shortcut_Shift|#PB_Shortcut_Tab, #Event_ShiftTabKey)
EndIf
If IsMenu(TabKey\Menu)
BindMenuEvent(TabKey\Menu, #Event_TabKey, @Event_Tab())
BindMenuEvent(TabKey\Menu, #Event_ShiftTabKey, @Event_ShiftTab())
EndIf
EndIf
EndIf
EndProcedure
CompilerEndIf
;- Public Procedures
Procedure.i AddTabKeyGadget(GadgetID.i, Flags.i=#False, WindowID.i=#PB_Default)
; Flags: #InternalTabKey - ex. editor gadget will use the tab inside the gadget.
If AddMapElement(TabKey\Gadget(), Str(GadgetID))
If WindowID = #PB_Default : WindowID = GetWindowID(GadgetID) : EndIf
If FindMapElement(TabKey\Window(), Str(WindowID)) = #False
AddTabKeyWindow(WindowID)
EndIf
TabKey\Gadget()\Window = WindowID
TabKey\Gadget()\Flags = Flags
If AddElement(TabKey\Window(Str(WindowID))\Gadget())
TabKey\Window(Str(WindowID))\Gadget() = GadgetID
EndIf
CompilerIf #Enable_TabulationKey
If IsGadget(GadgetID)
BindGadgetEvent(GadgetID, @Event_Focus(), #PB_EventType_Focus)
BindGadgetEvent(GadgetID, @Event_LostFocus(), #PB_EventType_LostFocus)
EndIf
CompilerEndIf
ProcedureReturn #True
EndIf
ProcedureReturn #False
EndProcedure
Procedure.i AddTabKeyWindow(WindowID.i)
If IsWindow(WindowID)
If FindMapElement(TabKey\Window(), Str(WindowID))
CompilerIf #Enable_TabulationKey
TabKey\Menu = CreateMenu(#PB_Any, WindowID(WindowID))
If IsMenu(TabKey\Menu)
RemoveKeyboardShortcut(WindowID, #PB_Shortcut_Tab)
RemoveKeyboardShortcut(WindowID, #PB_Shortcut_Shift|#PB_Shortcut_Tab)
AddKeyboardShortcut(WindowID, #PB_Shortcut_Tab, #Event_TabKey)
AddKeyboardShortcut(WindowID, #PB_Shortcut_Shift|#PB_Shortcut_Tab, #Event_ShiftTabKey)
BindMenuEvent(TabKey\Menu, #Event_TabKey, @Event_Tab())
BindMenuEvent(TabKey\Menu, #Event_ShiftTabKey, @Event_ShiftTab())
EndIf
CompilerEndIf
ProcedureReturn #True
ElseIf AddMapElement(TabKey\Window(), Str(WindowID))
CompilerIf #Enable_TabulationKey
TabKey\Menu = CreateMenu(#PB_Any, WindowID(WindowID))
If IsMenu(TabKey\Menu)
RemoveKeyboardShortcut(WindowID, #PB_Shortcut_Tab)
RemoveKeyboardShortcut(WindowID, #PB_Shortcut_Shift|#PB_Shortcut_Tab)
AddKeyboardShortcut(WindowID, #PB_Shortcut_Tab, #Event_TabKey)
AddKeyboardShortcut(WindowID, #PB_Shortcut_Shift|#PB_Shortcut_Tab, #Event_ShiftTabKey)
BindMenuEvent(TabKey\Menu, #Event_TabKey, @Event_Tab())
BindMenuEvent(TabKey\Menu, #Event_ShiftTabKey, @Event_ShiftTab())
EndIf
CompilerEndIf
ProcedureReturn #True
EndIf
EndIf
ProcedureReturn #False
EndProcedure
Procedure.i RemoveTabKeyGadget(GadgetID.i, RestoreInternalTab.i=#False)
Protected WindowID = GetWindowID(GadgetID)
If FindMapElement(TabKey\Gadget(), Str(GadgetID))
If RestoreInternalTab.i=#False
ForEach TabKey\Window(Str(WindowID))\Gadget()
If TabKey\Window(Str(WindowID))\Gadget()=GadgetID
Break
EndIf
Next
DeleteElement(TabKey\Window(Str(WindowID))\Gadget(), 1)
DeleteMapElement(TabKey\Gadget(), Str(GadgetID))
LastElement(TabKey\Window(Str(WindowID))\Gadget())
Else
TabKey\Gadget()\Flags = #InternalTabKey
EndIf
EndIf
EndProcedure
Procedure UseTabKey(WindowID.i=#PB_Default)
Protected CountGadget, i
NewList Windows()
NewList Gadgets()
If WindowID=#PB_Default
GetWindowList(Windows())
ForEach Windows()
CountGadget= GetGadgetList(Gadgets(), WindowID(Windows()))
If CountGadget>0
ForEach Gadgets()
AddTabKeyGadget(Gadgets(),#False,Windows())
Next
EndIf
Next
Else
CountGadget= GetGadgetList(Gadgets(), WindowID(WindowID))
If CountGadget>0
ForEach Gadgets()
AddTabKeyGadget(Gadgets(),#False,WindowID)
Next
EndIf
EndIf
EndProcedure
; Procedure DebugMe()
; Debug TabKey\Window(Str(1))\Gadget()
; EndProcedure
EndModule
;- ----------------------------------------------------------------------------
;- Main
CompilerIf #PB_Compiler_IsMainFile
Enumeration Windows
#Window = 1
#Window2
EndEnumeration
Enumeration Gadgets
#Button = 1
#image
#Combo
#editor
#String
#Button2
#image2
#Combo2
#editor2
#String2
EndEnumeration
If OpenWindow(#Window, 50, 200, 310, 360, "TAB Module1", #PB_Window_SystemMenu|#PB_Window_SizeGadget)
ButtonGadget(#Button, 10, 15, 80, 24, "Button", #PB_Button_Toggle)
ImageGadget(#image, 110, 15, 80, 24, 0,#PB_Image_Border )
ComboBoxGadget(#Combo, 210, 15, 90, 24)
AddGadgetItem(#Combo, -1, "Test")
SetGadgetState(#Combo, 0)
EditorGadget(#editor,10,60,290,100)
StringGadget(#String,10,200,290,30,"")
OpenWindow(#Window2, 400, 200, 310, 360, "TAB Module2", #PB_Window_SystemMenu|#PB_Window_SizeGadget)
ButtonGadget(#Button2, 10, 15, 80, 24, "Button", #PB_Button_Toggle)
ImageGadget(#image2, 110, 15, 80, 24, 0,#PB_Image_Border )
ComboBoxGadget(#Combo2, 210, 15, 90, 24)
AddGadgetItem(#Combo2, -1, "Test")
SetGadgetState(#Combo2, 0)
EditorGadget(#editor2,10,60,290,100)
StringGadget(#String2,10,200,290,30,"")
;-TabKey Management
UseModule TabKey
;Choice 1: Full automatic
UseTabKey()
;Choice 2: Automatic only for one or more specified windows
; UseTabKey(#Window)
;Choice 3: Handle gadgets manually
; AddTabKeyGadget(#Button)
; AddTabKeyGadget(#image)
; AddTabKeyGadget(#Combo)
; AddTabKeyGadget(#editor);,#InternalTabKey
; AddTabKeyGadget(#String)
RemoveTabKeyGadget(#editor2, #True);editor gadget uses the tab inside the gadget.
SetActiveWindow(#Window)
Define Event
Repeat
Event = WaitWindowEvent()
Select Event
Case #PB_Event_Gadget
Select EventGadget()
Case #Button, #Combo To #String
Debug "ok"
Case #image
;Some gadgets have no focus event
Debug "ok ?"
Case #Combo
EndSelect
EndSelect
Until Event = #PB_Event_CloseWindow
CloseWindow(#Window)
EndIf
CompilerEndIf