[PB 6.00] Another TabBarGadget [Source]

Share your advanced PureBasic knowledge/code with the community.
User avatar
Mijikai
Addict
Addict
Posts: 1520
Joined: Sun Sep 11, 2016 2:17 pm

[PB 6.00] Another TabBarGadget [Source]

Post by Mijikai »

Another TabBarGadget

Maybe this is useful for someone :)
Its a more simplistic implementation of a TabBarGadget.
I did not use any platform specific code so this should also work on Linux and CheeseburgerOS.

If you look for something professional i suggest this:
http://forums.purebasic.com/english/vie ... f236ee0443

NEW Version (dev. 1.1):
http://forums.purebasic.com/english/vie ... 0e#p593390

Version (dev. 1.0):
http://forums.purebasic.com/english/vie ... 18#p593357

Version (dev. 0.5):

How it looks:
Image

Example:

Code: Select all

EnableExplicit

XIncludeFile "gadget_tab.pbi"

Procedure.i Main()
  Protected flags.i
  Protected btn.i
  Protected tab.i
  Protected cnt.i
  flags|#PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_MinimizeGadget
  flags|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget
  If OpenWindow(0,0,0,600,400,#Null$,flags)
    btn = ButtonGadget(#PB_Any,200,100,200,30,"Add Tab")
    tab = TabGadgetCreate(0,0,0)
    TabGadgetAdd(tab,"Tab 1",#True,123)
    TabGadgetAdd(tab,"Tab 2",#False,456)
    TabGadgetAdd(tab,"Tab 3",#False,789)
    Repeat
      Select WaitWindowEvent()
        Case #TAB_EVENT
          Select TabGadgetEvent()
            Case #TAB_EVENT_CLOSED
              Debug "Closed: " + Str(TabGadgetEventData())
            Case #TAB_EVENT_SELECTED
              Debug "Selected: " + Str(TabGadgetEventData())
          EndSelect
        Case #PB_Event_Gadget
          Select EventGadget()
            Case tab
              TabGadgetUpdate(tab)
            Case btn
              TabGadgetAdd(tab,"Hello " + Str(cnt),#False,cnt)
              cnt + 1
          EndSelect
        Case #PB_Event_SizeWindow
          TabGadgetResize(tab,WindowWidth(0))
        Case #PB_Event_CloseWindow
          Break
      EndSelect
    ForEver
    CloseWindow(0)  
  EndIf  
  ProcedureReturn #Null
EndProcedure

Main()

End

Code:

Code: Select all

EnableExplicit

;TabGadget
;Version: dev 0.5
;Author: Mijikai
;Note: 
;- Most things are hardcoded!
;- Tabs can be scrolled with the mouse wheel and the left right buttons
;The left and right buttons have two modes (mouse left click/right click) ;)

UsePNGImageDecoder()

Structure TAB_RECT_STRUCT
  x.i
  y.i
  w.i
  h.i
EndStructure

Structure TAB_IMG_STRUCT
  id.i[7]
EndStructure

Structure TAB_ITEM_STRUCT
  text.s
  custom.i
  rect.TAB_RECT_STRUCT
EndStructure

Structure TAB_STRUCT
  window.i
  font.i
  canvas.i
  color.i
  *image.TAB_IMG_STRUCT
  rect.TAB_RECT_STRUCT
  *active.TAB_ITEM_STRUCT
  start.i
  stop.i
  min.i
  max.i
  offset.i
  List item.TAB_ITEM_STRUCT()
EndStructure

#TAB_EVENT = #PB_Event_FirstCustomValue
#TAB_EVENT_SELECTED = 1
#TAB_EVENT_CLOSED = 0

Procedure.i TabWindowColor(Window.i,*Color.Integer)
  If StartDrawing(WindowOutput(Window))
    *Color\i = Point(0,0)
    StopDrawing()
    ProcedureReturn #True
  EndIf
  ProcedureReturn #False
EndProcedure

Procedure.i TabGadgetCreate(Window.i,X.i,Y.i,Color.i = -1)
  Static init.i
  Static font.i
  Static img.TAB_IMG_STRUCT
  Protected *tab.TAB_STRUCT
  Protected save.i
  With *tab
    If Not init
      font = LoadFont(#PB_Any,"Consolas",10)
      If font
        img\id[0] = CatchImage(#PB_Any,?tab_img_0)
        img\id[1] = CatchImage(#PB_Any,?tab_img_1)
        img\id[2] = CatchImage(#PB_Any,?tab_img_2)
        img\id[3] = CatchImage(#PB_Any,?tab_img_3)
        img\id[4] = CatchImage(#PB_Any,?tab_img_4)
        img\id[5] = CatchImage(#PB_Any,?tab_img_5)
        img\id[6] = CatchImage(#PB_Any,?tab_img_6)
        For save = 0 To 6
          If img\id[save]
            init + 1
          EndIf
        Next
        init = Bool(init = 7)
      EndIf
    EndIf
    If init And Window < 0
      For save = 0 To 6
        If \image\id[save]
          FreeImage(\image\id[save])
        EndIf
      Next
      If font
        FreeFont(font)
      EndIf
      init = #False
    EndIf
    If IsWindow(Window) And init
      save = UseGadgetList(WindowID(Window))
      *tab = AllocateStructure(TAB_STRUCT)
      If *tab
        \window = Window
        \image = @img
        \font = font
        \rect\x = X
        \rect\y = Y
        \rect\h = 30
        \rect\w = WindowWidth(Window,#PB_Window_InnerCoordinate)
        \canvas = CanvasGadget(#PB_Any,\rect\x,\rect\y,\rect\w,\rect\h)
        If \canvas
          \color = Color
          If Color < 0
            TabWindowColor(window,@\color) 
          EndIf
          UseGadgetList(save)
          SetGadgetData(\canvas,*tab)
          ProcedureReturn \canvas
        EndIf
        FreeStructure(*tab)
        UseGadgetList(save)
      EndIf
    EndIf
    ProcedureReturn #Null
  EndWith
EndProcedure

Procedure.i TabGadgetUpdate(Gadget.i)
  Protected *tab.TAB_STRUCT
  Protected mouse_click.i
  Protected mouse_right.i
  Protected mouse_wheel.i
  Protected mouse_x.i
  Protected mouse_y.i
  Protected highlight.i
  Protected offset.i
  Protected close.i
  With *tab
    *tab = GetGadgetData(Gadget)
    mouse_x = GetGadgetAttribute(\canvas,#PB_Canvas_MouseX)
    mouse_y = GetGadgetAttribute(\canvas,#PB_Canvas_MouseY)
    Select EventType()
      Case #PB_EventType_LeftClick
        mouse_click = #True
      Case #PB_EventType_RightClick
        mouse_right = #True
      Case #PB_EventType_MouseLeave
        mouse_x = 0
        mouse_y = 0
    EndSelect
    mouse_wheel = GetGadgetAttribute(\canvas,#PB_Canvas_WheelDelta)
    If mouse_wheel < 0
      mouse_wheel = -128  
    ElseIf mouse_wheel > 0
      mouse_wheel = 128
    EndIf
    \start + mouse_wheel
    If \start < \min
      \start = \min
    ElseIf \start > \max
      \start = \max
    EndIf
    \offset = \start + 1
    If StartDrawing(CanvasOutput(\canvas))
      DrawingFont(FontID(\font))
      Box(0,0,OutputWidth(),OutputHeight(),\color)
      ForEach \item()
        DrawingMode(#PB_2DDrawing_AllChannels)
        highlight = Bool(mouse_x > \offset And mouse_x < (\offset + 128) And mouse_y > 5 And mouse_x < (\rect\w - 64))
        If highlight
          \item()\rect\x = \offset + 128 - 21
          \item()\rect\y = 11 - (highlight << 1)
          \item()\rect\w = \item()\rect\x + 14
          \item()\rect\h = \item()\rect\y + 14 
          If mouse_x > \item()\rect\x And mouse_x < \item()\rect\w And mouse_y > \item()\rect\y And mouse_y < \item()\rect\h And mouse_x < (\rect\w - 64)
            close = 1 + mouse_click
          ElseIf mouse_click 
            \active = @\item()
            PostEvent(#TAB_EVENT,1,\item()\custom)
          EndIf
        ElseIf \active = @\item()
          highlight = 1
        EndIf
        If close = 2
          If \active = @\item()
            \active = 0  
          EndIf
          PostEvent(#TAB_EVENT,0,\item()\custom)
          \stop - 128
          \min = - (\stop - 128)
          DeleteElement(\item())
          mouse_click = #False
        Else
          offset = highlight << 1
          DrawAlphaImage(ImageID(\image\id[0 + highlight + close]),\offset,5 - offset)
          DrawingMode(#PB_2DDrawing_Transparent)
          DrawText(\offset + 5,10 - offset,\item()\text,$666666)
          \offset + 128
        EndIf
        close = 0
      Next
      DrawingMode(#PB_2DDrawing_AllChannels)
      offset = 0
      highlight = 0
      If mouse_y > 2
        If mouse_x > (\rect\w - 32) And mouse_x < \rect\w
          offset = 1
          If mouse_click
            \start - 128  
          ElseIf mouse_right
            \start = \min
          EndIf
        ElseIf mouse_x > (\rect\w - 64) And mouse_x < (\rect\w - 32)
          highlight = 1
          If mouse_click
            \start + 128  
          ElseIf mouse_right
            \start = \max
          EndIf
        EndIf
      EndIf
      DrawAlphaImage(ImageID(\image\id[3 + highlight]),\rect\w - 64,2)
      DrawAlphaImage(ImageID(\image\id[5 + offset]),\rect\w - 32,2)
      StopDrawing()
      ProcedureReturn #True
    EndIf
    ProcedureReturn #False
  EndWith
EndProcedure

Procedure.i TabGadgetRelease(Gadget.i)
  Protected *tab.TAB_STRUCT
  With *tab
    *Tab = GetGadgetData(Gadget)
    FreeGadget(\canvas)
    FreeStructure(*Tab)
    ProcedureReturn #Null
  EndWith
EndProcedure

Procedure.i TabGadgetDestroy()
  TabGadgetCreate(-1,#Null,#Null)
  ProcedureReturn #Null
EndProcedure

Procedure.i TabGadgetEvent()
  ProcedureReturn EventWindow()  
EndProcedure

Procedure.i TabGadgetEventData()
  ProcedureReturn EventGadget()
EndProcedure

Procedure.i TabGadgetAdd(Gadget.i,Text.s,Active.i = #False,Custom.i = #Null)
  Protected *tab.TAB_STRUCT
  With *tab
    *tab = GetGadgetData(Gadget)
    If AddElement(\item())
      If Len(Text) > 14
        Text = Left(Text,12) + ".." 
      EndIf
      \item()\text = Text
      \item()\custom = Custom
      If Active
        \active = @\item()
      EndIf
      \min = - \stop
      \max = \rect\w - 128
      \stop + 128
      TabGadgetUpdate(Gadget)
      ProcedureReturn @\item()
    EndIf
    ProcedureReturn #Null
  EndWith
EndProcedure

Procedure.i TabGadgetResize(Gadget.i,Width.i)
  Protected *tab.TAB_STRUCT
  With *tab
    *tab = GetGadgetData(Gadget)
    ResizeGadget(\canvas,#PB_Ignore,#PB_Ignore,Width,#PB_Ignore)
    \rect\w = Width
    \max = \rect\w - 128
    TabGadgetUpdate(Gadget)
    ProcedureReturn #Null
  EndWith
EndProcedure

DataSection
  tab_img_0:
  IncludeBinary "bt0.png"
  tab_img_1:
  IncludeBinary "bt1.png"
  tab_img_2:
  IncludeBinary "bt2.png"
  tab_img_3:
  IncludeBinary "bl0.png"
  tab_img_4:
  IncludeBinary "bl1.png"
  tab_img_5:
  IncludeBinary "br0.png"
  tab_img_6:
  IncludeBinary "br1.png"
EndDataSection

Download (sources + images):
https://www.dropbox.com/s/jt7gtkyoo057e ... b.zip?dl=0
Last edited by Mijikai on Fri Jan 06, 2023 11:54 am, edited 4 times in total.
User avatar
idle
Always Here
Always Here
Posts: 5903
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: [PB 6.00] Another TabBarGadget [Source]

Post by idle »

looks good on windows 11
Hey I'm on a diet, don't mention cheeseburgers :lol:
User avatar
jacdelad
Addict
Addict
Posts: 2010
Joined: Wed Feb 03, 2021 12:46 pm
Location: Riesa

Re: [PB 6.00] Another TabBarGadget [Source]

Post by jacdelad »

Looks very, very nice. So nice, I put it into one file and made a module from it:

Code: Select all

;TabGadget
;Version: dev 0.5
;Author: Mijikai
;Note: 
;- Most things are hardcoded!
;- Tabs can be scrolled with the mouse wheel and the left right buttons
;The left and right buttons have two modes (mouse left click/right click) ;)

DeclareModule TabGadget
  Declare.i TabWindowColor(Window.i,*Color.Integer)  
  Declare.i TabGadgetCreate(Window.i,X.i,Y.i,Color.i = -1)
  Declare.i TabGadgetUpdate(Gadget.i)
  Declare.i TabGadgetRelease(Gadget.i)
  Declare.i TabGadgetDestroy()
  Declare.i TabGadgetEvent()
  Declare.i TabGadgetEventData()
  Declare.i TabGadgetAdd(Gadget.i,Text.s,Active.i = #False,Custom.i = #Null)
  Declare.i TabGadgetResize(Gadget.i,Width.i)
  #TAB_EVENT = #PB_Event_FirstCustomValue
  #TAB_EVENT_SELECTED = 1
  #TAB_EVENT_CLOSED = 0
EndDeclareModule

Module TabGadget
  EnableExplicit
  
  UsePNGImageDecoder()
  
  Structure TAB_RECT_STRUCT
    x.i
    y.i
    w.i
    h.i
  EndStructure
  
  Structure TAB_IMG_STRUCT
    id.i[7]
  EndStructure
  
  Structure TAB_ITEM_STRUCT
    text.s
    custom.i
    rect.TAB_RECT_STRUCT
  EndStructure
  
  Structure TAB_STRUCT
    window.i
    font.i
    canvas.i
    color.i
    *image.TAB_IMG_STRUCT
    rect.TAB_RECT_STRUCT
    *active.TAB_ITEM_STRUCT
    start.i
    stop.i
    min.i
    max.i
    offset.i
    List item.TAB_ITEM_STRUCT()
  EndStructure
  
  #TAB_EVENT = #PB_Event_FirstCustomValue
  #TAB_EVENT_SELECTED = 1
  #TAB_EVENT_CLOSED = 0
  
  Procedure.i TabWindowColor(Window.i,*Color.Integer)
    If StartDrawing(WindowOutput(Window))
      *Color\i = Point(0,0)
      StopDrawing()
      ProcedureReturn #True
    EndIf
    ProcedureReturn #False
  EndProcedure
  
  Procedure.i TabGadgetCreate(Window.i,X.i,Y.i,Color.i = -1)
    Static init.i
    Static font.i
    Static img.TAB_IMG_STRUCT
    Protected *tab.TAB_STRUCT
    Protected save.i
    With *tab
      If Not init
        font = LoadFont(#PB_Any,"Consolas",10)
        If font
          img\id[0] = CatchImage(#PB_Any,?tab_img_0)
          img\id[1] = CatchImage(#PB_Any,?tab_img_1)
          img\id[2] = CatchImage(#PB_Any,?tab_img_2)
          img\id[3] = CatchImage(#PB_Any,?tab_img_3)
          img\id[4] = CatchImage(#PB_Any,?tab_img_4)
          img\id[5] = CatchImage(#PB_Any,?tab_img_5)
          img\id[6] = CatchImage(#PB_Any,?tab_img_6)
          For save = 0 To 6
            If img\id[save]
              init + 1
            EndIf
          Next
          init = Bool(init = 7)
        EndIf
      EndIf
      If init And Window < 0
        For save = 0 To 6
          If \image\id[save]
            FreeImage(\image\id[save])
          EndIf
        Next
        If font
          FreeFont(font)
        EndIf
        init = #False
      EndIf
      If IsWindow(Window) And init
        save = UseGadgetList(WindowID(Window))
        *tab = AllocateStructure(TAB_STRUCT)
        If *tab
          \window = Window
          \image = @img
          \font = font
          \rect\x = X
          \rect\y = Y
          \rect\h = 30
          \rect\w = WindowWidth(Window,#PB_Window_InnerCoordinate)
          \canvas = CanvasGadget(#PB_Any,\rect\x,\rect\y,\rect\w,\rect\h)
          If \canvas
            \color = Color
            If Color < 0
              TabWindowColor(window,@\color) 
            EndIf
            UseGadgetList(save)
            SetGadgetData(\canvas,*tab)
            ProcedureReturn \canvas
          EndIf
          FreeStructure(*tab)
          UseGadgetList(save)
        EndIf
      EndIf
      ProcedureReturn #Null
    EndWith
  EndProcedure
  
  Procedure.i TabGadgetUpdate(Gadget.i)
    Protected *tab.TAB_STRUCT
    Protected mouse_click.i
    Protected mouse_right.i
    Protected mouse_wheel.i
    Protected mouse_x.i
    Protected mouse_y.i
    Protected highlight.i
    Protected offset.i
    Protected close.i
    With *tab
      *tab = GetGadgetData(Gadget)
      mouse_x = GetGadgetAttribute(\canvas,#PB_Canvas_MouseX)
      mouse_y = GetGadgetAttribute(\canvas,#PB_Canvas_MouseY)
      Select EventType()
        Case #PB_EventType_LeftClick
          mouse_click = #True
        Case #PB_EventType_RightClick
          mouse_right = #True
        Case #PB_EventType_MouseLeave
          mouse_x = 0
          mouse_y = 0
      EndSelect
      mouse_wheel = GetGadgetAttribute(\canvas,#PB_Canvas_WheelDelta)
      If mouse_wheel < 0
        mouse_wheel = -128  
      ElseIf mouse_wheel > 0
        mouse_wheel = 128
      EndIf
      \start + mouse_wheel
      If \start < \min
        \start = \min
      ElseIf \start > \max
        \start = \max
      EndIf
      \offset = \start + 1
      If StartDrawing(CanvasOutput(\canvas))
        DrawingFont(FontID(\font))
        Box(0,0,OutputWidth(),OutputHeight(),\color)
        ForEach \item()
          DrawingMode(#PB_2DDrawing_AllChannels)
          highlight = Bool(mouse_x > \offset And mouse_x < (\offset + 128) And mouse_y > 5 And mouse_x < (\rect\w - 64))
          If highlight
            \item()\rect\x = \offset + 128 - 21
            \item()\rect\y = 11 - (highlight << 1)
            \item()\rect\w = \item()\rect\x + 14
            \item()\rect\h = \item()\rect\y + 14 
            If mouse_x > \item()\rect\x And mouse_x < \item()\rect\w And mouse_y > \item()\rect\y And mouse_y < \item()\rect\h And mouse_x < (\rect\w - 64)
              close = 1 + mouse_click
            ElseIf mouse_click 
              \active = @\item()
              PostEvent(#TAB_EVENT,1,\item()\custom)
            EndIf
          ElseIf \active = @\item()
            highlight = 1
          EndIf
          If close = 2
            If \active = @\item()
              \active = 0  
            EndIf
            PostEvent(#TAB_EVENT,0,\item()\custom)
            \stop - 128
            \min = - (\stop - 128)
            DeleteElement(\item())
            mouse_click = #False
          Else
            offset = highlight << 1
            DrawAlphaImage(ImageID(\image\id[0 + highlight + close]),\offset,5 - offset)
            DrawingMode(#PB_2DDrawing_Transparent)
            DrawText(\offset + 5,10 - offset,\item()\text,$666666)
            \offset + 128
          EndIf
          close = 0
        Next
        DrawingMode(#PB_2DDrawing_AllChannels)
        offset = 0
        highlight = 0
        If mouse_y > 2
          If mouse_x > (\rect\w - 32) And mouse_x < \rect\w
            offset = 1
            If mouse_click
              \start - 128  
            ElseIf mouse_right
              \start = \min
            EndIf
          ElseIf mouse_x > (\rect\w - 64) And mouse_x < (\rect\w - 32)
            highlight = 1
            If mouse_click
              \start + 128  
            ElseIf mouse_right
              \start = \max
            EndIf
          EndIf
        EndIf
        DrawAlphaImage(ImageID(\image\id[3 + highlight]),\rect\w - 64,2)
        DrawAlphaImage(ImageID(\image\id[5 + offset]),\rect\w - 32,2)
        StopDrawing()
        ProcedureReturn #True
      EndIf
      ProcedureReturn #False
    EndWith
  EndProcedure
  
  Procedure.i TabGadgetRelease(Gadget.i)
    Protected *tab.TAB_STRUCT
    With *tab
      *Tab = GetGadgetData(Gadget)
      FreeGadget(\canvas)
      FreeStructure(*Tab)
      ProcedureReturn #Null
    EndWith
  EndProcedure
  
  Procedure.i TabGadgetDestroy()
    TabGadgetCreate(-1,#Null,#Null)
    ProcedureReturn #Null
  EndProcedure
  
  Procedure.i TabGadgetEvent()
    ProcedureReturn EventWindow()  
  EndProcedure
  
  Procedure.i TabGadgetEventData()
    ProcedureReturn EventGadget()
  EndProcedure
  
  Procedure.i TabGadgetAdd(Gadget.i,Text.s,Active.i = #False,Custom.i = #Null)
    Protected *tab.TAB_STRUCT
    With *tab
      *tab = GetGadgetData(Gadget)
      If AddElement(\item())
        If Len(Text) > 14
          Text = Left(Text,12) + ".." 
        EndIf
        \item()\text = Text
        \item()\custom = Custom
        If Active
          \active = @\item()
        EndIf
        \min = - \stop
        \max = \rect\w - 128
        \stop + 128
        TabGadgetUpdate(Gadget)
        ProcedureReturn @\item()
      EndIf
      ProcedureReturn #Null
    EndWith
  EndProcedure
  
  Procedure.i TabGadgetResize(Gadget.i,Width.i)
    Protected *tab.TAB_STRUCT
    With *tab
      *tab = GetGadgetData(Gadget)
      ResizeGadget(\canvas,#PB_Ignore,#PB_Ignore,Width,#PB_Ignore)
      \rect\w = Width
      \max = \rect\w - 128
      TabGadgetUpdate(Gadget)
      ProcedureReturn #Null
    EndWith
  EndProcedure
  
  DataSection
    tab_img_0:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$2200000080000000,$4688180000000208,$4E52740600000079,$37FF00FF00FF0053,$70090000007D1B58,$00C40E0000735948,$1B0E2B9501C40E00,$5441444993010000,$4082B2A19BEDDE68,$61020B7C778F8614,$2040D86081236183,$F003C081803C0D18,$30400F030600FA0A,$6C3060C182068C10,$BD860E05BC081820,$2EEB99DCEA38C3B3,$FFB4E73897FFAE77,$4475D75180433DDB,$D215808AD5AB4444,$F454EBAEA3CFD534,$6BD7AC3B1A209249,$6DB71C715AAC61AD,$B366F1C710EC688B,$58B172E5CB01BEF9,$E9A6965964FB1420,$20020407F6708898,$147EC3F9E790BFE0,$444B76ED96601045,$21CF9F3310BE1861,$08318B3C104120C0,$BF010A6CFF7EFD82,$2DB6DA2109DBB765,$3BA47A10848892CB,$0419B36628A28842,$E9D39659601FA118,$61F4DDC3870E8894,$1FEFBE0136F010CE,$F60109AAF47EC78F,$F749D3A779E7806E,$5636010B67EBCF3D,$A5201718043E8BD0,$021CE733E7CFF7EC,$C993954AAAA8092C,$A58042554A529744,$72EC63255318C415,$29739C38C82DE0B9,$A985DEEBAEBAEBA5,$20C021CE735D753B,$34D470F38E3B5D75,$C6300DE021908BCD,$300853679C2D4888,$8085497F3F385A8E,$004004004004013F,$7015CF8080004004,$02217C50C4115EBD,$81A54FFD016CF808,$C2330301B8F2544D,$A10DC57D9D431A0F,$0061F1CAF3DB0ED8,$AE444E4549000000
    Data.b $42,$60,$82
    tab_img_1:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$2200000080000000,$4688180000000208,$4E52740600000079,$37FF00FF00FF0053,$70090000007D1B58,$00C40E0000735948,$1B0E2B9501C40E00,$5441444995010000,$40C2AA319BEDDE68,$111636971FAF4514,$C48D882056422099,$2BA2236295A0B66A,$CE6D6648A20C2C10,$3330B1350479F22F,$87BBA6F32A9EF07E,$000039CE5B410377,$F2318C104839F3E6,$53A74FD115CE72DC,$DA1A2162C5861346,$9BE20559534D28C5,$CC06DFE5CB974D34,$B3C250C264C9B366,$DBB7006D318CAD5A,$CF9600368A7C718D,$5EBD611A03700587,$CBF00A63C78F9D3F,$C46BF7EFD001B366,$C71C48F00A23468C,$AB1E3C7C71C63155,$A76EDD97780EF96E,$6B40065965CE76B5,$DBB76F5AD132572D,$C03942F00DC870E1,$E9D3801EBD7ACB2C,$4C680A6734FB7774,$E8E5CF9F3DDBB740,$9137A0AC016BE18B,$8F322E5CBA28A300,$01B99CD3ED9CA8A2,$5DE4159CCD50570D,$ED7AF5F9E5E79E40,$A91A82B005AF3A74,$31C94A54716D6B20,$C4840A0AC8E2F3CF,$248F20AC251294AD,$FD125295EFDFB249,$E01424926D6B0CA3,$09AAB900A3ED6B11,$00060C180680EF99,$DCC8556DCD43870E,$2F1F5718FAA8C680,$C0103FD056187C05,$5006E1105600A00D,$808C3F1F7D056100,$ABEEE631805BBE02,$F475F8B6B5800929,$B9E5F4C84A199C8F,$8D07FCA784683FC5,$FD38C47D0CB40D5F,$4E4549000000006F
    Data.b $44,$AE,$42,$60,$82
    tab_img_2:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$2200000080000000,$4688180000000208,$4E52740600000079,$37FF00FF00FF0053,$70090000007D1B58,$00C40E0000735948,$1B0E2B9501C40E00,$5441444955010000,$30848A419BEDDE68,$0AE42282F14B4510,$832BA0AE55CA46E2,$C8B33367255C911B,$86CB46619B138210,$EBBFF9BD09A56FFE,$111113DEF0B44557,$BC75AD044044D34D,$201861FA41F7BC2E,$B0AA1B473CF30C8D,$B330DDC014B1CCC4,$FBEC71C602BBE631,$BAD68B2CB3C8A21E,$5453C721DF7DA222,$C05400D879F08444,$0EBAEF5D9AEBAC25,$66B5A16DB6CBDC06,$DC0616DB6DBF4377,$2E44CE799EBCD83B,$D41B5AC67F000F43,$C3F7FE32E1C4C637,$05443F0F6B5B330A,$CAD871FA263182DC,$D2A55E3FAE030CEA,$5FF41119D594D1A7,$61E8222DC382745E,$100FDB200D124110,$A8E667D514111241,$9040F44822096A7B,$2A5288DD0444F23E,$4A075A58B3CFCD44,$86359FFE31201829,$A69A02F434F19133,$519133DDD2BC9EC9,$4FA7EFF5D7519701,$00C0DE82202EF018,$00540104400C0054,$0484A3CFA088000C,$E73B5AD00DB3E030,$7476F0B9CE308420,$BAF1FAA48A21EF19,$7C681FA4F21A07C0,$250B9C2CBA4BC801,$4E45490000000077
    Data.b $44,$AE,$42,$60,$82
    tab_img_3:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1C00000020000000,$2AA08F0000000208,$4E52740600000075,$37FF00FF00FF0053,$70090000007D1B58,$00C40E0000735948,$1B0E2B9501C40E00,$5441444912010000,$30858E2196EDC748,$21C21091F6FB8610,$0204481515151510,$F493820408704081,$0810204081041C00,$47031C1515152104,$A5F6BEDD749A2BB6,$3BF99D13EA379ACD,$00004A521F6D27FD,$4BA0443C0A528000,$81F7DF7ABCE75D77,$C1D1F6FBEF6DB6A2,$C4FDBE69A6A28A33,$7FDED3C000011C71,$41861815B808F83D,$D471C6058ED75D73,$34C085A24995555C,$1532CC34B2CB9A4D,$4DE614517359E798,$73CF39A2CB2C091B,$39AAEBAC0B5ECF2B,$8DF933B391DB32CB,$A69A447F6952FE81,$76984DB76DB6F57A,$9DF7DE298C610840,$739CC63088FEE210,$100F7BB18C318CC5,$9084739CC5084242,$162A79E78421937B,$924945DFDD084042,$817FF83DE7D50D58,$8FB1C71A52929487,$F430C29A0575D7EA,$CABE0FE3AFD781D5,$00000563D985A83D,$42AE444E45490000
    Data.b $60,$82
    tab_img_4:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1C00000020000000,$2AA08F0000000208,$4E52740600000075,$37FF00FF00FF0053,$70090000007D1B58,$00C40E0000735948,$1B0E2B9501C40E00,$54414449FB000000,$50440E4196EDC748,$22111A38D8CB860C,$E0CE04E229621111,$74B1088444200E04,$A672E921667A4706,$85FEAFF31664E89D,$4F3CED156DFCBEF7,$064040AAAA800000,$75D7B7EDC5145D5E,$4494A573CF2E5C6D,$329D96599A698782,$54836C0000C38E3A,$956FC045F38A840F,$0CDE9A69F41A69A8,$839424927D16DB68,$638E3E875D75128C,$47D1EFBE826A29E2,$80C30C024D0F4451,$C603DECF56430C3E,$79A67701041F4471,$178257EB40C1FA63,$7149A69E9F1F7DF2,$C643CF3CA5280244,$AEBA2F65006CCF3C,$9A94DB8859658C8B,$F5D758C838E392E0,$B6C646DB6CA112CE,$C59659D97B00146D,$89A2F480F7FFAA1A,$04F177DF72CB2F4A,$E409F1D7FA4D0C72,$006FE4BD3F504A21,$AE444E4549000000
    Data.b $42,$60,$82
    tab_img_5:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1C00000020000000,$2AA08F0000000208,$4E52740600000075,$37FF00FF00FF0053,$70090000007D1B58,$00C40E0000735948,$1B0E2B9501C40E00,$54414449F5000000,$40830E21D6EDC748,$10207BD369D00510,$0810204089020408,$1EC0AE007040810E,$4007040810206381,$A2F920818E081020,$6AAEE90ED55A6682,$B24EC9979315FD47,$9659540C8AAAA97B,$01DA14515111B847,$76800888DCC1D4A5,$98131FAEBAF3CF20,$4194A532CB288800,$69A07BE07F0779E0,$07AE029E9A69CE1A,$2E20C5792492BEF0,$B6DA36638E200029,$AE8D88A288000FD5,$A36430C20003F4EB,$D808208000FD7BEF,$7E9AEDF023E18618,$F7D9C8E38C0D3DEC,$CF3D9C4D34C0CD7D,$ECE679E6009E3493,$C2CB2C0A4BB0AEBA,$5D6022D0F91C71D9,$1133BA9F6DB6CE57,$C1EFFE6D7C965960,$ED17FC19B6DB012F,$8EBE260F809CFEFB,$BBE609F5FACAE877,$4E45490000000036
    Data.b $44,$AE,$42,$60,$82
    tab_img_6:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1C00000020000000,$2AA08F0000000208,$4E52740600000075,$37FF00FF00FF0053,$70090000007D1B58,$00C40E0000735948,$1B0E2B9501C40E00,$54414449F5000000,$30840A4196EDC748,$114453978333450C,$82BC09E229714444,$E5711446E228873D,$8CA676712859D2D9,$C7D22EFD5FCCD999,$A020D75D47DA534F,$965940016376AAAA,$0009E63B529403B7,$288804CE28A2A028,$00165295CF3CA5D1,$08BE09824C41AD68,$659F21A69A8B7DF8,$BE9A69A635801199,$494334007AC3F8C3,$3713CD5B6DA31092,$9D75D1898E38AEC1,$D1888A28E47E0241,$90C30C4400FDFDF7,$D31D3E025C30C318,$F9238E368BE35ACB,$34D300CD6B2E0820,$A2D068539F7DF791,$E2ACC79E7BC99E79,$FCBAEBBC85965826,$C71DE4AEBAC02CD0,$E6DB6C8B56333A31,$8413D5303DFFCD8F,$0917F8EDB6D80825,$8EBE242D019E7EED,$90F3411D4382D12F,$4E45490000000056
    Data.b $44,$AE,$42,$60,$82
  EndDataSection
EndModule

CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
  UseModule TabGadget
  
  Procedure.i Main()
    Protected flags.i
    Protected btn.i
    Protected tab.i
    Protected cnt.i
    flags|#PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_MinimizeGadget
    flags|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget
    If OpenWindow(0,0,0,600,400,#Null$,flags)
      btn = ButtonGadget(#PB_Any,200,100,200,30,"Add Tab")
      tab = TabGadgetCreate(0,0,0)
      TabGadgetAdd(tab,"Tab 1",#True,123)
      TabGadgetAdd(tab,"Tab 2",#False,456)
      TabGadgetAdd(tab,"Tab 3",#False,789)
      Repeat
        Select WaitWindowEvent()
          Case #TAB_EVENT
            Select TabGadgetEvent()
              Case #TAB_EVENT_CLOSED
                Debug "Closed: " + Str(TabGadgetEventData())
              Case #TAB_EVENT_SELECTED
                Debug "Selected: " + Str(TabGadgetEventData())
            EndSelect
          Case #PB_Event_Gadget
            Select EventGadget()
              Case tab
                TabGadgetUpdate(tab)
              Case btn
                TabGadgetAdd(tab,"Hello " + Str(cnt),#False,cnt)
                cnt + 1
            EndSelect
          Case #PB_Event_SizeWindow
            TabGadgetResize(tab,WindowWidth(0))
          Case #PB_Event_CloseWindow
            Break
        EndSelect
      ForEver
      CloseWindow(0)  
    EndIf  
    ProcedureReturn #Null
  EndProcedure
  
  Main()
CompilerEndIf
Also, I would like to mention a few things (if you wish to improve it):
I don't know if #PB_Event_FirstCustomValue conflicts with other modules.
You can scroll the tabs even if there's nothing to scroll (plenty of space available).
It would be nicer (at least in my eyes) if you would create the graphics "on the fly", maybe also using system defined colors.

This is not a demand-list, just a todo-list if I would develop this!
Good morning, that's a nice tnetennba!

PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
User avatar
Mijikai
Addict
Addict
Posts: 1520
Joined: Sun Sep 11, 2016 2:17 pm

Re: [PB 6.00] Another TabBarGadget [Source]

Post by Mijikai »

Thank you both :)

@idle, i have the same problem :P

@jacdelad
Yes, #TAB_EVENT could conflict with other 3rd party code that also uses custom events.
#PB_Event_FirstCustomValue is the first event value available that doesnt conflict with PB events.
Therefore its best to check and adust this value before using the gadget :)
Maybe a function to set the event value would be better - not sure.
System colors would be nice but also OS dependant i will think about it.

For the next update i try to:
- limit the mouse wheel scrolling
- use on the fly graphics
- change to variable length tabs
- add a width control
- add a function to get the active item
User avatar
Mijikai
Addict
Addict
Posts: 1520
Joined: Sun Sep 11, 2016 2:17 pm

Re: [PB 6.00] Another TabBarGadget [Source]

Post by Mijikai »

Update (dev. 1.0):

Changes:
- graphics are created on the fly
- scrolling with the mouse wheel is fixed
- gadget width can now be set (resizing is fixed)
- tabs can now have variable sizes (optionally set a max Chr limit)
- support for fixed aka. static tabs
- support for images in tabs (16 x 16)
- events are safe to use
- more functions (see TabBarGadget include)

Preview:
Image

Have fun :D

Example:

Code: Select all

EnableExplicit

XIncludeFile "TabBarGadget.pbi"

Procedure.i Main()
  Protected flags.i
  Protected tab.i
  Protected img.i
  flags|#PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_MinimizeGadget
  flags|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget
  If OpenWindow(0,0,0,640,420,#Null$,flags)
    tab = TabBarGadgetCreate(0,10,20,600,8,1)
    If tab
      TabBarGadgetAdd(tab,#Null,"Hello World!",0,1)
      TabBarGadgetAdd(tab,#Null,"233")
      TabBarGadgetAdd(tab,#Null,"gjglkjhljl")
      TabBarGadgetAdd(tab,#Null,"Top_Secrect.txt",1)
      Repeat
        Select WaitWindowEvent()
          Case #PB_Event_Gadget
            If EventGadget() = tab
              Select EventType()
                Case #PB_EventType_TabBar_Add
                  Debug "ADD!"
                  Debug TabBarGadgetItemText(tab,EventData())
                Case #PB_EventType_TabBar_Select
                  Debug "ACTIVE!"
                  Debug TabBarGadgetItemText(tab,EventData())
                Case #PB_EventType_TabBar_Remove
                  Debug "REMOVE!"
                  Debug TabBarGadgetItemText(tab,EventData())
              EndSelect
              TabBarGadgetUpdate(tab)
            EndIf
          Case #PB_Event_SizeWindow
            TabBarGadgetResize(tab)
          Case #PB_Event_CloseWindow
            Break
        EndSelect
      ForEver
      TabBarGadgetFree(tab)
      TabBarGadgetRelease()
    EndIf
    CloseWindow(0)  
  EndIf  
  ProcedureReturn #Null
EndProcedure

Main()

End
TabBarGadget Include:

Code: Select all

EnableExplicit

;TabBarGadget
;Version: dev 1.0
;Author: Mijikai

;Functions:

;TabBarGadgetCreate(Window.i,X.i,Y.i,Width.i = #Null,Limit.i = #Null,Active.i = #Null)
;-------------------------------------------------------------------------------------
;FUNCTION:    Creates a TabBar Gadget
;Window.i     = A PB Window (not the WindowID)
;Y and Y.i    = Gadget position in pixel
;Width.i      = Gadget width in pixel (height is fixed @ 32)
;Limit.i      = How many characters (Tab Text) are allowed - if #Null there is no limit!
;Active.i     = If #True the next available Tab becomes active if the current active Tab is removed 
;RETURNS:     #Null or a Gadget number on success

;TabBarGadgetAdd(Gadget.i,Image.i,Text.s,Active.i = #False,Fixed.i = #False,*Parameter = #Null)
;----------------------------------------------------------------------------------------------
;FUNCTION:    Adds a new Tab/Item to the TabBar
;Gadget.i     = A TabBar Gadget number
;Image.i      = A ImageID if the Tab should display an Image (16 x 16 pixels - will be automatically resized)
;Text.s       = The Text/Name of the new TabBar
;Active.i     = If #True the Tab will be the active Tab
;Fixed.i      = If #True the Tab cant be closed aka. is static (it can removed with TabBarGadgetRemove())
;Parameter.i  = A custom parameter that is associated with the Tab (can be obtained with TabBarGadgetItem())
;RETURNS:     #Null or a Tab number (needed for TabBarGadgetItem())

;TabBarGadgetUpdate(Gadget.i)
;----------------------------
;FUNCTION:    Updates the TabBar and handles TabBar events
;Gadget.i     = A TabBar Gadget number
;RETURNS:     #True / #False

;TabBarGadgetUpdate(Gadget.i)
;----------------------------
;FUNCTION:    Updates the TabBar and handles TabBar events
;Gadget.i     = A TabBar Gadget number
;RETURNS:     #True / #False

;TabBarGadgetResize(Gadget.i)
;----------------------------
;FUNCTION:    Automatically resized the TabBar according to the associated Window size
;Gadget.i     = A TabBar Gadget number
;RETURNS      #True / #False

;TabBarGadgetItemCount(Gadget.i)
;-------------------------------
;FUNCTION:    Returns the number of Tabs
;Gadget.i     = A TabBar Gadget number
;RETURNS:     Number of Tabs

;TabBarGadgetItem(Gadget.i,*Item.TAB_ITEM_STRUCT = #Null,*Parameter.Integer = #Null)
;----------------------------------------------------------------------------------
;FUNCTION:    Returns the currently active Tab and optionally the custom value associated with the Tab
;Gadget.i     = A TabBar Gadget number
;*Item        = A Tab number  (if #Null the currently active tab is used)
;*Parameter.i = If specified will obtain the custom parameter associated with the Tab
;RETURNS      = #Null or a Gadget number on success

;TabBarGadgetItemText(Gadget.i,*Item.TAB_ITEM_STRUCT = #Null)
;----------------------------------------------------------------------------------
;FUNCTION:    Returns the assciated Text of the supplied Tab number or the currently active Tab
;Gadget.i     = A TabBar Gadget number
;*Item        = A Tab number (if #Null the currently active tab is used)
;RETURNS      = #Null$ or the associated Text on success

;TabBarGadgetRemove(Gadget.i,*Item = #Null,Active.i = #False)
;------------------------------------------------------------
;FUNCTION:    Removes a Tab either the currently active one or the one specified with *Item (will not generate a event!)
;Gadget.i     = A TabBar Gadget number
;*Item        = A Tab number (if #Null the currently active tab is used)

;TabBarGadgetFree(Gadget.i)
;FUNCTION:    Removes the TabBar Gadget
;Gadget.i     = A TabBar Gadget number
;RETURNS:     Nothing

;TabBarGadgetRelease()
;FUNCTION:    Releases all resources (only call when all TabBar Gadgets are freed!)
;RETURNS:     Nothing

;TabBarGadgetItemRemoved(Gadget.i)
;FUNCTION:    The last removed Tab / Item number
;RETURNS:     The last removed Tab / Item number or #Null

;ALL OTHER FUNCTIONS ARE FOR INTERNAL USE!

;-----------------------------------------

;EVENTS:
;There are three events that are associated with the Gadget number (so its safe to use)

;EVENT INFO:
;EventGadget() can be checked against the TabBar Gadget number
;EventWindow() can be checked against window associated with the TabBar

;EVENT TYPES:
;EventType()  

;#PB_EventType_TabBar_Add
;-> will be fired if a Tab is added

;#PB_EventType_TabBar_Select
;-> will be fired if a new Tab has become active

;#PB_EventType_TabBar_Remove
;-> will be fired if a tab is removed

;NOTE:
;EventData() will hold the Item / Tab number (for all three TabBar events)

;If the event is #PB_EventType_TabBar_Remove - EventData() will contain a pseudo Tab number!
;Which can be used with TabBarGadgetItem() and TabBarGadgetItemText()!

;To identify the Tab (to obtain its original number) a call to TabBarGadgetItemRemoved() is needed!
;This is because the original Tab / Item is already destroyed.
;The contents of the Tab are copied into a transfer buffer that is only valid until the next call to TabGadgetUpdate()!

;In general process all events before calling TabBarGadgetUpdate() again!

UsePNGImageDecoder() 

Structure TAB_RECT_STRUCT
  x.i
  y.i
  w.i
  h.i
EndStructure

Structure TAB_IMGAGE_STRUCT
  region.i[14]
EndStructure

Structure TAB_ITEM_STRUCT
  fixed.i
  img.i
  text.s
  text_full.s
  *parameter
  span.i
  size.i
  offset.i
EndStructure

Structure TAB_STRUCT
  window.i
  canvas.i
  font.i
  color.i
  mouse_x.i
  mouse_y.i
  mouse_right.i
  mouse_left.i
  mouse_wheel.i
  mouse_state.i
  remove.i
  *this
  limit.i
  width.i
  rect.TAB_RECT_STRUCT
  *image.TAB_IMGAGE_STRUCT
  *last
  remember.TAB_ITEM_STRUCT
  *offset.TAB_ITEM_STRUCT
  *active.TAB_ITEM_STRUCT
  List item.TAB_ITEM_STRUCT()
EndStructure

#PB_EventType_TabBar_Add = #PB_EventType_FirstCustomValue
#PB_EventType_TabBar_Select = #PB_EventType_TabBar_Add + 1
#PB_EventType_TabBar_Remove = #PB_EventType_TabBar_Select + 1

Procedure.i TabBarGadgetDraw(X.i,Y.i,ColorA.i,ColorB.i,ColorC.i,ColorD.i)
  DrawingMode(#PB_2DDrawing_AllChannels|#PB_2DDrawing_Gradient)      
  FrontColor(ColorA)
  BackColor(ColorB)
  LinearGradient(0,X + 70,0,Y)    
  RoundBox(X,Y,63,40,4,4) 
  RoundBox(X + 64,Y,63,40,4,4)
  Box(X + 128,Y,56,28); 
  DrawingMode(#PB_2DDrawing_AllChannels|#PB_2DDrawing_Outlined)
  RoundBox(X,Y,63,40,4,4,ColorC)
  RoundBox(X + 64,Y,63,40,4,4,ColorC)
  Box(X + 128,Y,56,28,ColorC)
  Box(X + 128,Y,29,28,ColorC)
  Box(X + 128,Y,28,28,ColorC) 
  LineXY(X + 137,Y + 14,X + 143,Y + 8,ColorC)
  LineXY(X + 137,Y + 14,X + 143,Y + 20,ColorC)
  LineXY(X + 138,Y + 14,X + 144,Y + 8,ColorD)
  LineXY(X + 138,Y + 14,X + 144,Y + 20,ColorD)
  LineXY(X + 173,Y + 14,X + 167,Y + 8,ColorC)
  LineXY(X + 173,Y + 14,X + 167,Y + 20,ColorC)
  LineXY(X + 174,Y + 14,X + 168,Y + 8,ColorD)
  LineXY(X + 174,Y + 14,X + 168,Y + 20,ColorD)
  LineXY(X + 45,Y + 9,X + 52,Y + 16,ColorC)
  LineXY(X + 45,Y + 16,X + 52,Y + 9,ColorC)
  LineXY(X + 108,Y + 9,X + 115,Y + 16,ColorC)
  LineXY(X + 110,Y + 9,X + 117,Y + 16,ColorC)
  LineXY(X + 108,Y + 16,X + 115,Y + 9,ColorC)
  LineXY(X + 110,Y + 16,X + 117,Y + 9,ColorC)
  LineXY(X + 109,Y + 9,X + 116,Y + 16,ColorD)
  LineXY(X + 109,Y + 16,X + 116,Y + 9,ColorD)
  RoundBox(X + 42,Y + 6,14,14,3,3,ColorC)
  RoundBox(X + 106,Y + 6,14,14,3,3,ColorD)
  ProcedureReturn #Null
EndProcedure

Procedure.i TabBarGadgetImage(Image.i = #Null,Button.i = #Null,Index.i = #Null)
  Protected img.i
  Protected rect.TAB_RECT_STRUCT
  If Image
    If Index < 4
      ProcedureReturn GrabImage(Image,#PB_Any,Index * 32,Button * 40,32,40)
    ElseIf Index < 5
      ProcedureReturn GrabImage(Image,#PB_Any,16,Button * 40,8,40)
    Else
      ProcedureReturn GrabImage(Image,#PB_Any,128 + ((Index - 5) * 28),Button * 40,28,28)
    EndIf
  Else
    img = CreateImage(#PB_Any,192,128,32,#PB_Image_Transparent)
    If img
      If StartDrawing(ImageOutput(img))
        TabBarGadgetDraw(0,0,$FFFFFFFF,$FFBBBBBB,$FFAAAAAA,$FF888888)
        TabBarGadgetDraw(0,40,$FFEEEEEE,$FFBBBBBB,$FFAAAAAA,$FF888888)
        StopDrawing()
      Else
        FreeImage(img)
        img = #Null
      EndIf
    EndIf
  EndIf
  ProcedureReturn img
EndProcedure

Procedure.i TabBarGadgetWindowColor(Window.i,*Color.Integer)
  If StartDrawing(WindowOutput(Window))
    *Color\i = Point(0,0)
    StopDrawing()
    ProcedureReturn #True
  EndIf
  ProcedureReturn #False
EndProcedure

Procedure.i TabBarGadgetCreate(Window.i,X.i,Y.i,Width.i = #Null,Limit.i = #Null,Active.i = #Null)
  Static init.i
  Static font.i
  Static image.TAB_IMGAGE_STRUCT
  Protected index.i
  Protected state.i
  Protected *tab.TAB_STRUCT
  With *tab
    If Not init
      font = LoadFont(#PB_Any,"Consolas",10)
      init = TabBarGadgetImage()
      If init
        For index = 0 To 6
          image\region[index] = TabBarGadgetImage(init,0,index)
          image\region[index + 7] = TabBarGadgetImage(init,1,index) 
          state + Bool(image\region[index] And image\region[index + 7])
        Next
        FreeImage(init)
        init = Bool(state = 7) 
      EndIf
      If init = #False
        ProcedureReturn TabBarGadgetCreate(-1,#Null,#Null)
      EndIf
    EndIf
    If Window < 0
      If font
        FreeFont(font)
      EndIf
      For index = 0 To 13
        If image\region[index]
          FreeImage(image\region[index])
        EndIf
      Next
      init = #False
      ProcedureReturn #Null
    EndIf
    If init And IsWindow(Window)
      *tab = AllocateStructure(TAB_STRUCT)
      If *tab
        \window = Window
        \width = WindowWidth(Window,#PB_Window_InnerCoordinate)
        \rect\x = X
        \rect\y = Y
        If Width > 0
          \rect\w = Width - \rect\x  
        Else
          \rect\w = \width - \rect\x
        EndIf
        \rect\h = 32
        \limit = Limit
        TabBarGadgetWindowColor(Window,@\color)
        state = UseGadgetList(WindowID(\window))
        \canvas = CanvasGadget(#PB_Any,\rect\x,\rect\y,\rect\w,\rect\h)
        If \canvas
          \font = font
          \image = @image
          \remove = Active
          If StartDrawing(CanvasOutput(\canvas))
            Box(0,0,\rect\w,\rect\h,\color)
            StopDrawing()
            SetGadgetData(\canvas,*tab)
            UseGadgetList(state)
            ProcedureReturn \canvas
          EndIf
          FreeGadget(\canvas)
        EndIf
        UseGadgetList(state)
        FreeStructure(*tab)
      EndIf
    EndIf
    ProcedureReturn #Null
  EndWith  
EndProcedure

Procedure.i TabBarGadgetUpdateButtons(*Tab.TAB_STRUCT)
  Protected index_x.i
  Protected index_y.i
  With *Tab
    index_x = 12
    index_y = 13
    If \mouse_state = 2 And ListSize(\item()) 
      If \mouse_x > \rect\w - 28
        index_y = 6
        If \mouse_left 
          ChangeCurrentElement(\item(),\offset)
          If NextElement(\item())
            \offset = @\item() 
          EndIf
        ElseIf \mouse_right
          If LastElement(\item())
            \offset = @\item()  
          EndIf
        EndIf
      Else
        index_x = 5
        If \mouse_left
          ChangeCurrentElement(\item(),\offset)
          If PreviousElement(\item())
            \offset = @\item() 
          EndIf
        ElseIf \mouse_right
          If FirstElement(\item())
            \offset = @\item()  
          EndIf
        EndIf
      EndIf
    EndIf
    DrawImage(ImageID(\image\region[index_x]),\rect\w - 56,0)
    DrawImage(ImageID(\image\region[index_y]),\rect\w - 28,0)
    ProcedureReturn #Null
  EndWith
EndProcedure

Procedure.i TabBarGadgetUpdateTabs(*Tab.TAB_STRUCT,*Item.TAB_ITEM_STRUCT,*Offset.Integer)
  Protected *new.TAB_ITEM_STRUCT
  Protected rect.TAB_RECT_STRUCT
  Protected exit.TAB_RECT_STRUCT
  Protected highlight.i
  Protected close.i
  Protected click.i
  Protected offset.i
  With *Tab
    rect\x = *Offset\i
    rect\y = 6
    rect\w = *Offset\i + *Item\size
    rect\h = 32
    If rect\x < \rect\w
      If *Item = \active
        highlight = 1
        rect\y - 4
      EndIf
      If \mouse_state = 1
        If \mouse_x > rect\x And \mouse_x < rect\w And \mouse_y >= rect\y And \mouse_y < rect\h
          exit\x = *Offset\i + *Item\span + 42
          exit\y = rect\y + 6
          exit\w = exit\x + 14
          exit\h = exit\y + 14
          If *item\fixed = #Null
            If \mouse_x > exit\x And \mouse_x < exit\w And \mouse_y > exit\y And \mouse_y < exit\h
              close = 2
            EndIf
          EndIf
          If \mouse_left Or \mouse_right
            If \active <> *Item And close <> 2
              PostEvent(#PB_Event_Gadget,\window,\canvas,#PB_EventType_TabBar_Select,@\item())  
            EndIf
            \active = *Item
            click = #True
          EndIf
          \mouse_state = 0
        EndIf
      EndIf
      If click And close
        \this = *Item
      Else
        If *Item\fixed And Not *Item\img
          offset = 9
        EndIf
        rect\w = *Offset\i + *Item\span + *Item\offset
        If highlight
          DrawAlphaImage(ImageID(\image\region[0]),rect\x,rect\y)
          DrawAlphaImage(ImageID(\image\region[1 + close]),rect\w + 32,rect\y)
          DrawImage(ImageID(\image\region[4]),rect\x + 32,rect\y,*Item\span + *Item\fixed + *Item\offset,40)
          DrawText(rect\x + *Item\offset + 6 + offset,rect\y + 6,*Item\text,$FF666666)
          If *Item\img
            DrawImage(*Item\img,rect\x + 6,rect\y + 6,16,16)
          EndIf
        Else
          DrawAlphaImage(ImageID(\image\region[7]),rect\x,rect\y)
          DrawAlphaImage(ImageID(\image\region[8 + close]),rect\w + 32,rect\y)
          DrawImage(ImageID(\image\region[11]),rect\x + 32,rect\y,*Item\span + *Item\fixed + *Item\offset,40)
          DrawText(rect\x + *Item\offset + 6 + offset,rect\y + 6,*Item\text,$FF666666) 
          If *Item\img
            DrawImage(*Item\img,rect\x + 6,rect\y + 6,16,16)
          EndIf
        EndIf
      EndIf
      *Offset\i + *Item\size
    EndIf
    ProcedureReturn #Null
  EndWith
EndProcedure

Procedure.i TabBarGadgetUpdate(Gadget.i)
  Protected *tab.TAB_STRUCT
  Protected offset.i
  With *tab
    *tab = GetGadgetData(Gadget)
    \mouse_left = 0
    \mouse_right = 0
    \mouse_wheel = 0
    Select EventType()
      Case #PB_EventType_MouseMove
        \mouse_x = GetGadgetAttribute(\canvas,#PB_Canvas_MouseX)
        \mouse_y = GetGadgetAttribute(\canvas,#PB_Canvas_MouseY)
      Case #PB_EventType_LeftClick
        \mouse_left = #True
      Case #PB_EventType_RightClick
        \mouse_right = #True
      Case #PB_EventType_MouseWheel
        \mouse_wheel = GetGadgetAttribute(\canvas,#PB_Canvas_WheelDelta) 
      Case #PB_EventType_MouseLeave
        \mouse_x = 0
        \mouse_y = 0
    EndSelect
    \mouse_state = 0
    If \mouse_x > \rect\w - 56 And \mouse_y =< 28
      \mouse_state = 2
    Else
      \mouse_state = 1  
    EndIf
    If ListSize(\item())
      If \mouse_wheel
        ChangeCurrentElement(\item(),\offset)
        If \mouse_wheel < 0
          If PreviousElement(\item())
            \offset = @\item()
          EndIf
        Else
          If NextElement(\item())
            \offset = @\item()  
          EndIf
        EndIf
      EndIf
    EndIf
    If StartDrawing(CanvasOutput(\canvas))
      DrawingFont(FontID(\font))
      DrawingMode(#PB_2DDrawing_Transparent)
      Box(0,0,\rect\w,\rect\h,\color)
      If \offset
        ChangeCurrentElement(\item(),\offset)
        Repeat
          TabBarGadgetUpdateTabs(*tab,@\item(),@offset)
        Until NextElement(\item()) = #Null
      EndIf
      TabBarGadgetUpdateButtons(*tab)
      StopDrawing()
      If \this
        ChangeCurrentElement(\item(),\this)
        offset = NextElement(\item())
        If offset = #Null
          offset = PreviousElement(\item())
        EndIf
        If \offset = \this
          \offset = offset
        EndIf
        If \active = \this
          \active = #Null
          If \remove
            \active = offset
            If offset
              PostEvent(#PB_Event_Gadget,\window,\canvas,#PB_EventType_TabBar_Select,offset)
            EndIf    
          EndIf
        EndIf
        \last = \this
        CopyStructure(\this,@\remember,TAB_ITEM_STRUCT)
        ChangeCurrentElement(\item(),\this)
        DeleteElement(\item())
        \this = #Null
        PostEvent(#PB_Event_Gadget,\window,\canvas,#PB_EventType_TabBar_Remove,@\remember)
      EndIf
      ProcedureReturn #True
    EndIf
    ProcedureReturn #False
  EndWith
EndProcedure

Procedure.i TabBarGadgetResize(Gadget.i)
  Protected *tab.TAB_STRUCT
  Protected width.i
  With *tab
    *tab = GetGadgetData(Gadget)
    width = WindowWidth(\window,#PB_Window_InnerCoordinate) 
    \rect\w = \rect\w + (width - \width)
    \width = width
    ResizeGadget(\canvas,#PB_Ignore,#PB_Ignore,\rect\w,#PB_Ignore)
    ProcedureReturn TabBarGadgetUpdate(Gadget)
  EndWith
EndProcedure

Procedure.i TabBarGadgetAdd(Gadget.i,Image.i,Text.s,Active.i = #False,Fixed.i = #False,*Parameter = #Null)
  Protected *tab.TAB_STRUCT
  With *tab
    *tab = GetGadgetData(Gadget)
    If AddElement(\item())   
      \item()\text_full = Text
      If \limit
        If Len(Text) > \limit
          Text = Left(Text,\limit) + "..."
        EndIf
      EndIf
      If StartDrawing(CanvasOutput(\canvas))
        DrawingFont(FontID(\font))
        \item()\span = TextWidth(Text) - 32
        StopDrawing()
        If Fixed
          \item()\fixed = 28
        EndIf
        If Image
          \item()\img = Image
          \item()\offset + 20
        EndIf
        \item()\span + Bool((\item()\span % 2) <> 0)
        \item()\size = \item()\span + \item()\offset + 64
        \item()\text = Text
        \item()\parameter = *Parameter
        If Active
          \active = @\item()
        EndIf
        If \offset = #Null
          \offset = @\item()
        EndIf
        TabBarGadgetUpdate(Gadget)
        PostEvent(#PB_Event_Gadget,\window,\canvas,#PB_EventType_TabBar_Add,@\item())
        If Active
          PostEvent(#PB_Event_Gadget,\window,\canvas,#PB_EventType_TabBar_Select,@\item())
        EndIf
        ProcedureReturn @\item()
      EndIf
      DeleteElement(\item())
    EndIf
    ProcedureReturn #Null
  EndWith
EndProcedure

Procedure.i TabBarGadgetItemCount(Gadget.i)
  Protected *tab.TAB_STRUCT
  With *tab
    *tab = GetGadgetData(Gadget)
    ProcedureReturn ListSize(\item())
  EndWith
EndProcedure

Procedure.i TabBarGadgetItem(Gadget.i,*Item.TAB_ITEM_STRUCT = #Null,*Parameter.Integer = #Null)
  Protected *tab.TAB_STRUCT
  With *tab
    *tab = GetGadgetData(Gadget)
    If *Item = #Null
      *Item = \active
    EndIf
    If *Item And *Parameter
      *Parameter\i = *Item\parameter
    EndIf
    ProcedureReturn *Item
  EndWith
EndProcedure

Procedure.i TabBarGadgetItemRemoved(Gadget.i)
  Protected *tab.TAB_STRUCT
  With *tab
    *tab = GetGadgetData(Gadget)
    ProcedureReturn *tab\last
  EndWith
EndProcedure

Procedure.s TabBarGadgetItemText(Gadget.i,*Item.TAB_ITEM_STRUCT = #Null)
  Protected *tab.TAB_STRUCT
  With *tab
    *tab = GetGadgetData(Gadget)
    If *Item = #Null
      *Item = \active
    EndIf
    If *Item
      ProcedureReturn *Item\text_full
    EndIf
    ProcedureReturn #Null$
  EndWith
EndProcedure

Procedure.i TabBarGadgetRemove(Gadget.i,*Item = #Null,Active.i = #False)
  Protected *tab.TAB_STRUCT
  Protected *new
  With *tab
    *tab = GetGadgetData(Gadget)
    If *Item = #Null
      *Item = \active
    EndIf
    If *Item And ListSize(\item())
      ChangeCurrentElement(\item(),*Item)
      If NextElement(\item())
        *new = @\item()
      ElseIf PreviousElement(\item())
        *new = @\item()
      EndIf
      If \offset = *Item
        \offset = *new
      EndIf
      If \active = *Item
        \active = #Null
        If Active Or \remove
          \active = *new
        EndIf
      EndIf
      ChangeCurrentElement(\item(),*Item)
      DeleteElement(\item())
      TabBarGadgetUpdate(Gadget)
    EndIf
    ProcedureReturn *new
  EndWith
EndProcedure

Procedure.i TabBarGadgetFree(Gadget.i)
  Protected *tab.TAB_STRUCT
  Protected state.i
  With *tab
    *tab = GetGadgetData(Gadget)
    state = UseGadgetList(WindowID(\window))
    FreeGadget(\canvas)
    UseGadgetList(state)
    FreeStructure(*tab)
    ProcedureReturn #Null
  EndWith
EndProcedure

Procedure.i TabBarGadgetRelease()
  ProcedureReturn TabBarGadgetCreate(-1,#Null,#Null)
EndProcedure

User avatar
jacdelad
Addict
Addict
Posts: 2010
Joined: Wed Feb 03, 2021 12:46 pm
Location: Riesa

Re: [PB 6.00] Another TabBarGadget [Source]

Post by jacdelad »

Hi Mijikai,
it's getting better and better. Are you planning on releasing more controls for a unified look? Are you planning to make it customizable or just "as is"?

Also, I'd like to mention two things:
- You can still scroll the tabs out of the window when scrolling isn't needed.
- When hovering a tab it would be cool to give it a "hover"-look.
Good morning, that's a nice tnetennba!

PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
User avatar
Mijikai
Addict
Addict
Posts: 1520
Joined: Sun Sep 11, 2016 2:17 pm

Re: [PB 6.00] Another TabBarGadget [Source]

Post by Mijikai »

Update (dev. 1.1):

Changes:
- scrolling is only allowed if there are tabs that are not visible
- added indicators to the scroll buttons that the user is aware of tabs that are not visible
- added optional highlighting when hovering over a tab

Code: Select all

EnableExplicit

;TabBarGadget
;Version: dev 1.1
;Author: Mijikai

;Functions:

;TabBarGadgetCreate(Window.i,X.i,Y.i,Width.i = #Null,Limit.i = #Null,Hover.i = #False,Active.i = #Null)
;-------------------------------------------------------------------------------------
;FUNCTION:    Creates a TabBar Gadget
;Window.i     = A PB Window (not the WindowID)
;Y and Y.i    = Gadget position in pixel
;Width.i      = Gadget width in pixel (height is fixed @ 32)
;Hover.i      = Tabs will be highlighted if the cursor is over them
;Limit.i      = How many characters (Tab Text) are allowed - if #Null there is no limit!
;Active.i     = If #True the next available Tab becomes active if the current active Tab is removed 
;RETURNS:     #Null or a Gadget number on success

;TabBarGadgetAdd(Gadget.i,Image.i,Text.s,Active.i = #False,Fixed.i = #False,*Parameter = #Null)
;----------------------------------------------------------------------------------------------
;FUNCTION:    Adds a new Tab/Item to the TabBar
;Gadget.i     = A TabBar Gadget number
;Image.i      = A ImageID if the Tab should display an Image (16 x 16 pixels - will be automatically resized)
;Text.s       = The Text/Name of the new TabBar
;Active.i     = If #True the Tab will be the active Tab
;Fixed.i      = If #True the Tab cant be closed aka. is static (it can removed with TabBarGadgetRemove())
;Parameter.i  = A custom parameter that is associated with the Tab (can be obtained with TabBarGadgetItem())
;RETURNS:     #Null or a Tab number (needed for TabBarGadgetItem())

;TabBarGadgetUpdate(Gadget.i)
;----------------------------
;FUNCTION:    Updates the TabBar and handles TabBar events
;Gadget.i     = A TabBar Gadget number
;RETURNS:     #True / #False

;TabBarGadgetUpdate(Gadget.i)
;----------------------------
;FUNCTION:    Updates the TabBar and handles TabBar events
;Gadget.i     = A TabBar Gadget number
;RETURNS:     #True / #False

;TabBarGadgetResize(Gadget.i)
;----------------------------
;FUNCTION:    Automatically resized the TabBar according to the associated Window size
;Gadget.i     = A TabBar Gadget number
;RETURNS      #True / #False

;TabBarGadgetItemCount(Gadget.i)
;-------------------------------
;FUNCTION:    Returns the number of Tabs
;Gadget.i     = A TabBar Gadget number
;RETURNS:     Number of Tabs

;TabBarGadgetItem(Gadget.i,*Item.TAB_ITEM_STRUCT = #Null,*Parameter.Integer = #Null)
;----------------------------------------------------------------------------------
;FUNCTION:    Returns the currently active Tab and optionally the custom value associated with the Tab
;Gadget.i     = A TabBar Gadget number
;*Item        = A Tab number  (if #Null the currently active tab is used)
;*Parameter.i = If specified will obtain the custom parameter associated with the Tab
;RETURNS      = #Null or a Gadget number on success

;TabBarGadgetItemText(Gadget.i,*Item.TAB_ITEM_STRUCT = #Null)
;----------------------------------------------------------------------------------
;FUNCTION:    Returns the assciated Text of the supplied Tab number or the currently active Tab
;Gadget.i     = A TabBar Gadget number
;*Item        = A Tab number (if #Null the currently active tab is used)
;RETURNS      = #Null$ or the associated Text on success

;TabBarGadgetRemove(Gadget.i,*Item = #Null,Active.i = #False)
;------------------------------------------------------------
;FUNCTION:    Removes a Tab either the currently active one or the one specified with *Item (will not generate a event!)
;Gadget.i     = A TabBar Gadget number
;*Item        = A Tab number (if #Null the currently active tab is used)

;TabBarGadgetFree(Gadget.i)
;FUNCTION:    Removes the TabBar Gadget
;Gadget.i     = A TabBar Gadget number
;RETURNS:     Nothing

;TabBarGadgetRelease()
;FUNCTION:    Releases all resources (only call when all TabBar Gadgets are freed!)
;RETURNS:     Nothing

;TabBarGadgetItemRemoved(Gadget.i)
;FUNCTION:    The last removed Tab / Item number
;RETURNS:     The last removed Tab / Item number or #Null

;ALL OTHER FUNCTIONS ARE FOR INTERNAL USE!

;-----------------------------------------

;EVENTS:
;There are three events that are associated with the Gadget number (so its safe to use)

;EVENT INFO:
;EventGadget() can be checked against the TabBar Gadget number
;EventWindow() can be checked against window associated with the TabBar

;EVENT TYPES:
;EventType()  

;#PB_EventType_TabBar_Add
;-> will be fired if a Tab is added

;#PB_EventType_TabBar_Select
;-> will be fired if a new Tab has become active

;#PB_EventType_TabBar_Remove
;-> will be fired if a tab is removed

;NOTE:
;EventData() will hold the Item / Tab number (for all three TabBar events)

;If the event is #PB_EventType_TabBar_Remove - EventData() will contain a pseudo Tab number!
;Which can be used with TabBarGadgetItem() and TabBarGadgetItemText()!

;To identify the Tab (to obtain its original number) a call to TabBarGadgetItemRemoved() is needed!
;This is because the original Tab / Item is already destroyed.
;The contents of the Tab are copied into a transfer buffer that is only valid until the next call to TabGadgetUpdate()!

;In general process all events before calling TabBarGadgetUpdate() again!

UsePNGImageDecoder() 

Structure TAB_RECT_STRUCT
  x.i
  y.i
  w.i
  h.i
EndStructure

Structure TAB_IMGAGE_STRUCT
  region.i[14]
EndStructure

Structure TAB_ITEM_STRUCT
  fixed.i
  img.i
  text.s
  text_full.s
  *parameter
  span.i
  size.i
  offset.i
EndStructure

Structure TAB_STRUCT
  window.i
  canvas.i
  font.i
  color.i
  mouse_x.i
  mouse_y.i
  mouse_right.i
  mouse_left.i
  mouse_wheel.i
  mouse_state.i
  hover.i
  remove.i
  limit.i
  width.i
  scroll.i
  scroll_pos.i
  rect.TAB_RECT_STRUCT
  *image.TAB_IMGAGE_STRUCT
  *first.TAB_ITEM_STRUCT
  *last.TAB_ITEM_STRUCT
  *removed.TAB_ITEM_STRUCT
  remember.TAB_ITEM_STRUCT
  *offset.TAB_ITEM_STRUCT
  *active.TAB_ITEM_STRUCT
  List item.TAB_ITEM_STRUCT()
EndStructure

#PB_EventType_TabBar_Add = #PB_EventType_FirstCustomValue
#PB_EventType_TabBar_Select = #PB_EventType_TabBar_Add + 1
#PB_EventType_TabBar_Remove = #PB_EventType_TabBar_Select + 1

Procedure.i TabBarGadgetDraw(X.i,Y.i,ColorA.i,ColorB.i,ColorC.i,ColorD.i)
  DrawingMode(#PB_2DDrawing_AllChannels|#PB_2DDrawing_Gradient)      
  FrontColor(ColorA)
  BackColor(ColorB)
  LinearGradient(0,X + 70,0,Y)    
  RoundBox(X,Y,63,40,4,4) 
  RoundBox(X + 64,Y,63,40,4,4)
  Box(X + 128,Y,56,28); 
  DrawingMode(#PB_2DDrawing_AllChannels|#PB_2DDrawing_Outlined)
  RoundBox(X,Y,63,40,4,4,ColorC)
  RoundBox(X + 64,Y,63,40,4,4,ColorC)
  Box(X + 128,Y,56,28,ColorC)
  Box(X + 128,Y,29,28,ColorC)
  Box(X + 128,Y,28,28,ColorC) 
  LineXY(X + 137,Y + 14,X + 143,Y + 8,ColorC)
  LineXY(X + 137,Y + 14,X + 143,Y + 20,ColorC)
  LineXY(X + 138,Y + 14,X + 144,Y + 8,ColorD)
  LineXY(X + 138,Y + 14,X + 144,Y + 20,ColorD)
  LineXY(X + 173,Y + 14,X + 167,Y + 8,ColorC)
  LineXY(X + 173,Y + 14,X + 167,Y + 20,ColorC)
  LineXY(X + 174,Y + 14,X + 168,Y + 8,ColorD)
  LineXY(X + 174,Y + 14,X + 168,Y + 20,ColorD)
  LineXY(X + 45,Y + 9,X + 52,Y + 16,ColorC)
  LineXY(X + 45,Y + 16,X + 52,Y + 9,ColorC)
  LineXY(X + 108,Y + 9,X + 115,Y + 16,ColorC)
  LineXY(X + 110,Y + 9,X + 117,Y + 16,ColorC)
  LineXY(X + 108,Y + 16,X + 115,Y + 9,ColorC)
  LineXY(X + 110,Y + 16,X + 117,Y + 9,ColorC)
  LineXY(X + 109,Y + 9,X + 116,Y + 16,ColorD)
  LineXY(X + 109,Y + 16,X + 116,Y + 9,ColorD)
  RoundBox(X + 42,Y + 6,14,14,3,3,ColorC)
  RoundBox(X + 106,Y + 6,14,14,3,3,ColorD)
  ProcedureReturn #Null
EndProcedure

Procedure.i TabBarGadgetImage(Image.i = #Null,Button.i = #Null,Index.i = #Null)
  Protected img.i
  Protected rect.TAB_RECT_STRUCT
  If Image
    If Index < 4
      ProcedureReturn GrabImage(Image,#PB_Any,Index * 32,Button * 40,32,40)
    ElseIf Index < 5
      ProcedureReturn GrabImage(Image,#PB_Any,16,Button * 40,8,40)
    Else
      ProcedureReturn GrabImage(Image,#PB_Any,128 + ((Index - 5) * 28),Button * 40,28,28)
    EndIf
  Else
    img = CreateImage(#PB_Any,192,128,32,#PB_Image_Transparent)
    If img
      If StartDrawing(ImageOutput(img))
        TabBarGadgetDraw(0,0,$FFFFFFFF,$FFBBBBBB,$FFAAAAAA,$FF888888)
        TabBarGadgetDraw(0,40,$FFEEEEEE,$FFBBBBBB,$FFAAAAAA,$FF888888)
        StopDrawing()
      Else
        FreeImage(img)
        img = #Null
      EndIf
    EndIf
  EndIf
  ProcedureReturn img
EndProcedure

Procedure.i TabBarGadgetWindowColor(Window.i,*Color.Integer)
  If StartDrawing(WindowOutput(Window))
    *Color\i = Point(0,0)
    StopDrawing()
    ProcedureReturn #True
  EndIf
  ProcedureReturn #False
EndProcedure

Procedure.i TabBarGadgetCreate(Window.i,X.i,Y.i,Width.i = #Null,Limit.i = #Null,Hover.i = #False,Active.i = #Null)
  Static init.i
  Static font.i
  Static image.TAB_IMGAGE_STRUCT
  Protected index.i
  Protected state.i
  Protected *tab.TAB_STRUCT
  With *tab
    If Not init
      font = LoadFont(#PB_Any,"Consolas",10)
      init = TabBarGadgetImage()
      If init
        For index = 0 To 6
          image\region[index] = TabBarGadgetImage(init,0,index)
          image\region[index + 7] = TabBarGadgetImage(init,1,index) 
          state + Bool(image\region[index] And image\region[index + 7])
        Next
        FreeImage(init)
        init = Bool(state = 7) 
      EndIf
      If init = #False
        ProcedureReturn TabBarGadgetCreate(-1,#Null,#Null)
      EndIf
    EndIf
    If Window < 0
      If font
        FreeFont(font)
      EndIf
      For index = 0 To 13
        If image\region[index]
          FreeImage(image\region[index])
        EndIf
      Next
      init = #False
      ProcedureReturn #Null
    EndIf
    If init And IsWindow(Window)
      *tab = AllocateStructure(TAB_STRUCT)
      If *tab
        \window = Window
        \width = WindowWidth(Window,#PB_Window_InnerCoordinate)
        \rect\x = X
        \rect\y = Y
        If Width > 0
          \rect\w = Width - \rect\x  
        Else
          \rect\w = \width - \rect\x
        EndIf
        \rect\h = 32
        \limit = Limit
        TabBarGadgetWindowColor(Window,@\color)
        state = UseGadgetList(WindowID(\window))
        \canvas = CanvasGadget(#PB_Any,\rect\x,\rect\y,\rect\w,\rect\h)
        If \canvas
          \font = font
          \hover = Hover
          \image = @image
          \remove = Active
          If StartDrawing(CanvasOutput(\canvas))
            Box(0,0,\rect\w,\rect\h,\color)
            StopDrawing()
            SetGadgetData(\canvas,*tab)
            UseGadgetList(state)
            ProcedureReturn \canvas
          EndIf
          FreeGadget(\canvas)
        EndIf
        UseGadgetList(state)
        FreeStructure(*tab)
      EndIf
    EndIf
    ProcedureReturn #Null
  EndWith  
EndProcedure

Procedure.i TabBarGadgetUpdateButtons(*Tab.TAB_STRUCT)
  Protected index_x.i
  Protected index_y.i
  With *Tab
    index_x = 12
    index_y = 13
    If \mouse_state = 2 And ListSize(\item()) And (\scroll > \width Or \first <> \offset)
      If \mouse_x > \rect\w - 28
        index_y = 6
        If \mouse_left 
          ChangeCurrentElement(\item(),\offset)
          If NextElement(\item())
            \offset = @\item() 
          EndIf
        ElseIf \mouse_right
          If LastElement(\item())
            \offset = @\item()  
          EndIf
        EndIf
      Else
        index_x = 5
        If \mouse_left
          ChangeCurrentElement(\item(),\offset)
          If PreviousElement(\item())
            \offset = @\item() 
          EndIf
        ElseIf \mouse_right
          If FirstElement(\item())
            \offset = @\item()  
          EndIf
        EndIf
      EndIf
    EndIf
    DrawImage(ImageID(\image\region[index_x]),\rect\w - 56,0)
    DrawImage(ImageID(\image\region[index_y]),\rect\w - 28,0)
    If \scroll_pos < 0
      Box(\rect\w - 40,8,1,13,$FF888888)
    EndIf
    If \scroll + \scroll_pos > \width
      Box(\rect\w - 17,8,1,13,$FF888888)   
    EndIf
    ProcedureReturn #Null
  EndWith
EndProcedure

Procedure.i TabBarGadgetUpdateTabs(*Tab.TAB_STRUCT,*Item.TAB_ITEM_STRUCT,*Offset.Integer)
  Protected *new.TAB_ITEM_STRUCT
  Protected rect.TAB_RECT_STRUCT
  Protected exit.TAB_RECT_STRUCT
  Protected highlight.i
  Protected hover.i
  Protected close.i
  Protected click.i
  Protected offset.i
  With *Tab
    rect\x = *Offset\i
    rect\y = 6
    rect\w = *Offset\i + *Item\size
    rect\h = 32
    If rect\x < \rect\w
      If *Item = \active
        highlight = 1
        rect\y - 4
      EndIf
      hover = 7
      If \mouse_state = 1
        If \mouse_x > rect\x And \mouse_x < rect\w And \mouse_y >= rect\y And \mouse_y < rect\h
          exit\x = *Offset\i + *Item\span + 42
          exit\y = rect\y + 6
          exit\w = exit\x + 14
          exit\h = exit\y + 14
          If \hover
            hover = 0
          EndIf
          If *item\fixed = #Null
            If \mouse_x > exit\x And \mouse_x < exit\w And \mouse_y > exit\y And \mouse_y < exit\h
              close = 2
            EndIf
          EndIf
          If \mouse_left Or \mouse_right
            If \active <> *Item And close <> 2
              PostEvent(#PB_Event_Gadget,\window,\canvas,#PB_EventType_TabBar_Select,@\item())  
            EndIf
            \active = *Item
            click = #True
          EndIf
          \mouse_state = 0
        EndIf
      EndIf
      If click And close
        \removed = *Item
      Else
        If *Item\fixed And Not *Item\img
          offset = 9
        EndIf
        rect\w = *Offset\i + *Item\span + *Item\offset
        If highlight
          DrawAlphaImage(ImageID(\image\region[0]),rect\x,rect\y)
          DrawAlphaImage(ImageID(\image\region[1 + close]),rect\w + 32,rect\y)
          DrawImage(ImageID(\image\region[4]),rect\x + 32,rect\y,*Item\span + *Item\fixed + *Item\offset,40)
          DrawText(rect\x + *Item\offset + 6 + offset,rect\y + 6,*Item\text,$FF666666)
          If *Item\img
            DrawImage(*Item\img,rect\x + 6,rect\y + 6,16,16)
          EndIf
        Else
          DrawAlphaImage(ImageID(\image\region[hover]),rect\x,rect\y)
          DrawAlphaImage(ImageID(\image\region[hover + 1 + close]),rect\w + 32,rect\y)
          DrawImage(ImageID(\image\region[hover + 4]),rect\x + 32,rect\y,*Item\span + *Item\fixed + *Item\offset,40)
          DrawText(rect\x + *Item\offset + 6 + offset,rect\y + 6,*Item\text,$FF666666) 
          If *Item\img
            DrawImage(*Item\img,rect\x + 6,rect\y + 6,16,16)
          EndIf
        EndIf
      EndIf
      *Offset\i + *Item\size
    EndIf
    ProcedureReturn #Null
  EndWith
EndProcedure

Procedure.i TabBarGadgetUpdate(Gadget.i)
  Protected *tab.TAB_STRUCT
  Protected offset.i
  With *tab
    *tab = GetGadgetData(Gadget)
    \removed = #Null
    \scroll_pos = 0
    \mouse_left = 0
    \mouse_right = 0
    \mouse_wheel = 0
    Select EventType()
      Case #PB_EventType_MouseMove
        \mouse_x = GetGadgetAttribute(\canvas,#PB_Canvas_MouseX)
        \mouse_y = GetGadgetAttribute(\canvas,#PB_Canvas_MouseY)
      Case #PB_EventType_LeftClick
        \mouse_left = #True
      Case #PB_EventType_RightClick
        \mouse_right = #True
      Case #PB_EventType_MouseWheel
        \mouse_wheel = GetGadgetAttribute(\canvas,#PB_Canvas_WheelDelta) 
      Case #PB_EventType_MouseLeave
        \mouse_x = 0
        \mouse_y = 0
    EndSelect
    \mouse_state = 0
    If \mouse_x > \rect\w - 56 And \mouse_y =< 28
      \mouse_state = 2
    Else
      \mouse_state = 1  
    EndIf
    If ListSize(\item()) 
      \first = FirstElement(\item())
      \last = LastElement(\item())
      If \first <> \offset Or \scroll > \width
        If \mouse_wheel
          ChangeCurrentElement(\item(),\offset)
          If \mouse_wheel < 0
            If PreviousElement(\item())
              \offset = @\item()
            EndIf
          Else
            If NextElement(\item())
              \offset = @\item()  
            EndIf
          EndIf
        EndIf
      EndIf
    EndIf
    If StartDrawing(CanvasOutput(\canvas))
      DrawingFont(FontID(\font))
      DrawingMode(#PB_2DDrawing_Transparent)
      Box(0,0,\rect\w,\rect\h,\color)
      If \offset
        ChangeCurrentElement(\item(),\offset)
        Repeat
          TabBarGadgetUpdateTabs(*tab,@\item(),@offset)
          \scroll_pos + \item()\size
        Until NextElement(\item()) = #Null
        \scroll_pos = -(\scroll - \scroll_pos)
      EndIf
      TabBarGadgetUpdateButtons(*tab)
      StopDrawing()
      If \removed
        ChangeCurrentElement(\item(),\removed)
        offset = NextElement(\item())
        If offset = #Null
          offset = PreviousElement(\item())
        EndIf
        If \offset = \removed
          \offset = offset
        EndIf
        If \active = \removed
          \active = #Null
          If \remove
            \active = offset
            If offset
              PostEvent(#PB_Event_Gadget,\window,\canvas,#PB_EventType_TabBar_Select,offset)
            EndIf    
          EndIf
        EndIf
        \scroll - \removed\size
        CopyStructure(\removed,@\remember,TAB_ITEM_STRUCT)
        ChangeCurrentElement(\item(),\removed)
        DeleteElement(\item())
        PostEvent(#PB_Event_Gadget,\window,\canvas,#PB_EventType_TabBar_Remove,@\remember)
      EndIf
      ProcedureReturn #True
    EndIf
    ProcedureReturn #False
  EndWith
EndProcedure

Procedure.i TabBarGadgetResize(Gadget.i)
  Protected *tab.TAB_STRUCT
  Protected width.i
  With *tab
    *tab = GetGadgetData(Gadget)
    width = WindowWidth(\window,#PB_Window_InnerCoordinate) 
    \rect\w = \rect\w + (width - \width)
    \width = width
    ResizeGadget(\canvas,#PB_Ignore,#PB_Ignore,\rect\w,#PB_Ignore)
    ProcedureReturn TabBarGadgetUpdate(Gadget)
  EndWith
EndProcedure

Procedure.i TabBarGadgetAdd(Gadget.i,Image.i,Text.s,Active.i = #False,Fixed.i = #False,*Parameter = #Null)
  Protected *tab.TAB_STRUCT
  With *tab
    *tab = GetGadgetData(Gadget)
    If AddElement(\item())   
      \item()\text_full = Text
      If \limit
        If Len(Text) > \limit
          Text = Left(Text,\limit) + "..."
        EndIf
      EndIf
      If StartDrawing(CanvasOutput(\canvas))
        DrawingFont(FontID(\font))
        \item()\span = TextWidth(Text) - 32
        StopDrawing()
        If Fixed
          \item()\fixed = 28
        EndIf
        If Image
          \item()\img = Image
          \item()\offset + 20
        EndIf
        \item()\span + Bool((\item()\span % 2) <> 0)
        \item()\size = \item()\span + \item()\offset + 64
        \item()\text = Text
        \item()\parameter = *Parameter
        If Active
          \active = @\item()
        EndIf
        If \offset = #Null
          \offset = @\item()
        EndIf
        \scroll + \item()\size
        TabBarGadgetUpdate(Gadget)
        PostEvent(#PB_Event_Gadget,\window,\canvas,#PB_EventType_TabBar_Add,@\item())
        If Active
          PostEvent(#PB_Event_Gadget,\window,\canvas,#PB_EventType_TabBar_Select,@\item())
        EndIf
        ProcedureReturn @\item()
      EndIf
      DeleteElement(\item())
    EndIf
    ProcedureReturn #Null
  EndWith
EndProcedure

Procedure.i TabBarGadgetItemCount(Gadget.i)
  Protected *tab.TAB_STRUCT
  With *tab
    *tab = GetGadgetData(Gadget)
    ProcedureReturn ListSize(\item())
  EndWith
EndProcedure

Procedure.i TabBarGadgetItem(Gadget.i,*Item.TAB_ITEM_STRUCT = #Null,*Parameter.Integer = #Null)
  Protected *tab.TAB_STRUCT
  With *tab
    *tab = GetGadgetData(Gadget)
    If *Item = #Null
      *Item = \active
    EndIf
    If *Item And *Parameter
      *Parameter\i = *Item\parameter
    EndIf
    ProcedureReturn *Item
  EndWith
EndProcedure

Procedure.i TabBarGadgetItemRemoved(Gadget.i)
  Protected *tab.TAB_STRUCT
  With *tab
    *tab = GetGadgetData(Gadget)
    ProcedureReturn *tab\removed
  EndWith
EndProcedure

Procedure.s TabBarGadgetItemText(Gadget.i,*Item.TAB_ITEM_STRUCT = #Null)
  Protected *tab.TAB_STRUCT
  With *tab
    *tab = GetGadgetData(Gadget)
    If *Item = #Null
      *Item = \active
    EndIf
    If *Item
      ProcedureReturn *Item\text_full
    EndIf
    ProcedureReturn #Null$
  EndWith
EndProcedure

Procedure.i TabBarGadgetRemove(Gadget.i,*Item.TAB_ITEM_STRUCT = #Null,Active.i = #False)
  Protected *tab.TAB_STRUCT
  Protected *new
  With *tab
    *tab = GetGadgetData(Gadget)
    If *Item = #Null
      *Item = \active
    EndIf
    If *Item And ListSize(\item())
      ChangeCurrentElement(\item(),*Item)
      If NextElement(\item())
        *new = @\item()
      ElseIf PreviousElement(\item())
        *new = @\item()
      EndIf
      If \offset = *Item
        \offset = *new
      EndIf
      If \active = *Item
        \active = #Null
        If Active Or \remove
          \active = *new
        EndIf
      EndIf
      \scroll - *Item\size
      ChangeCurrentElement(\item(),*Item)
      DeleteElement(\item())
      TabBarGadgetUpdate(Gadget)
    EndIf
    ProcedureReturn *new
  EndWith
EndProcedure

Procedure.i TabBarGadgetFree(Gadget.i)
  Protected *tab.TAB_STRUCT
  Protected state.i
  With *tab
    *tab = GetGadgetData(Gadget)
    state = UseGadgetList(WindowID(\window))
    FreeGadget(\canvas)
    UseGadgetList(state)
    FreeStructure(*tab)
    ProcedureReturn #Null
  EndWith
EndProcedure

Procedure.i TabBarGadgetRelease()
  ProcedureReturn TabBarGadgetCreate(-1,#Null,#Null)
EndProcedure
Have fun :)

@jacdelad thank you,
currently i have no plans for other gadgets but i would not rule it out.
I needed a TabBarGadget for a editor thingy that im working on so i decided to give it a try.
If i make it too customizeable it will become huge quickly which is what i wanted to avoid.
The easiest solution is see would be a custom drawing callback (all colors moved into a struct).
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: [PB 6.00] Another TabBarGadget [Source]

Post by Kwai chang caine »

Very nice and usefull
Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
Axolotl
Addict
Addict
Posts: 838
Joined: Wed Dec 31, 2008 3:36 pm

Re: [PB 6.00] Another TabBarGadget [Source]

Post by Axolotl »

Mijikai wrote: Wed Jan 04, 2023 6:57 pm ...
Yes, #TAB_EVENT could conflict with other 3rd party code that also uses custom events.
#PB_Event_FirstCustomValue is the first event value available that doesnt conflict with PB events.
...


I try to use named enumeration instead. In this case with custom events, I would do it like this.
Tricky thing with that: you must use and remember the (same) name of the enumeration.

Code: Select all

; ---== Code inside my includes ==---------------------------------------------
CompilerIf Defined(ECustomEvents, #PB_Enumeration) 
Enumeration ECustomEvents 
CompilerElse 
Enumeration ECustomEvents #PB_Event_FirstCustomValue 
CompilerEndIf 
  #EVENT_MyFirstCustomEvent 
EndEnumeration 
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
User avatar
Mijikai
Addict
Addict
Posts: 1520
Joined: Sun Sep 11, 2016 2:17 pm

Re: [PB 6.00] Another TabBarGadget [Source]

Post by Mijikai »

The problem was resolved in Version dev. 1.0, since then all TabBarGadget() events are safe to use and wont conflicts with other events.
User avatar
Mijikai
Addict
Addict
Posts: 1520
Joined: Sun Sep 11, 2016 2:17 pm

Re: [PB 6.00] Another TabBarGadget [Source]

Post by Mijikai »

@Kwai chang caine, Thank you :)
Post Reply