Seite 1 von 2

HyperTreeGadget 1.2

Verfasst: 30.05.2012 00:20
von Lambda
Hab vorhin angefangen ein eigenes TreeGadget zu schreiben. Zu handhaben mit Funktionen wie beim normalen TreeGadget.


Aktuell

- Zusätzliche Felder/Spalten (bekommen noch Events)
- Font für einzelne Items setzen
- Einrückung bestimmen
- Zwischenraum bestimmen
- Farben anpassen
- Einfach zu erweitern (z.B Hintergrund dazu kritzeln)
- Multi-Selection
- Höhe für einzelne Items bestimmen (gerade bei größeren Fonts)
- Skinnen
- Items sperren/entsperren (mit Vererbung)

To-Do
- Eingebautes Drag&Drop

Noch lange nicht fertig :D aber ein Anfang. Momentan, wenn man Icons nutzen will, mindestens 1 Feld für jedes Item mit dem Bild definieren.

Re: HyperTreeGadget

Verfasst: 30.05.2012 07:40
von RSBasic
Als erstes dachte ich, du wolltest HyperLinkGadget und TreeGadget kombinieren, nachdem ich deinen Titel dieses Threads las. :D

Wenn man auf Einträge klickt, reagiert er noch sehr träge. D.h. die Markierung erscheint immer etwas später. Und wenn die Maus rübergefahren wird (MouseHover), dann flackert die Markierung.
Einstellungen für Node-Linien und CheckBox fehlen noch.

Re: HyperTreeGadget

Verfasst: 30.05.2012 08:25
von Mr.L
Ich finds schon echt gut :allright:

Wenn jetzt noch Scrollbars hinzukommen und noch etwas an der performance-Schraube gedreht wird, ist es schon 'ne gute Sache.

hier noch ein Beispiel:

Code: Alles auswählen

;- Example
UsePNGImageDecoder()

Global index
Global fontSmall = LoadFont(#PB_Any, "arial", 10, #PB_Font_HighQuality)
Global fontBig = LoadFont(#PB_Any, "comic sans ms", 12, #PB_Font_Bold)
Global image1 = CreateImage(#PB_Any, 20,20,32|#PB_Image_Transparent)
StartDrawing(ImageOutput(image1))
  DrawingMode(#PB_2DDrawing_AlphaBlend|#PB_2DDrawing_AlphaClip)
  Circle(8,8,6,RGBA(170,200,240,200))
StopDrawing()

OpenWindow(0, 0, 0, 300, 400, "HyperTreeGadget", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
ButtonGadget(1, 5, 5, 70, 20, "Remove")

Procedure ScanPath(dir$, depth = 0)
	If index > 2500
		ProcedureReturn
	EndIf
	If index = 0
		AddHyperTreeItem(0, 0, dir$, depth, 1)
		SetHyperTreeItemAttribute(0, index, #HyperTree_Font, fontBig)
		AddHyperTreeItemField(0, index, 20, 20, image1)
		index + 1
		depth + 1
	EndIf
	dir = ExamineDirectory(#PB_Any, dir$, "*.*")
	If IsDirectory(dir)
		While NextDirectoryEntry(dir)
			If DirectoryEntryType(dir) = #PB_DirectoryEntry_Directory
				If DirectoryEntryName(dir) <> "." And DirectoryEntryName(dir) <> ".."
					AddHyperTreeItem(0, 0, DirectoryEntryName(dir), depth, 0, 25)
					SetHyperTreeItemAttribute(0, index, #HyperTree_Font, fontBig)
					AddHyperTreeItemField(0, index, 20, 20, image1)
					index + 1
					ScanPath(dir$ + "\" + DirectoryEntryName(dir), depth + 1)
				EndIf
			Else
				AddHyperTreeItem(0, 0, DirectoryEntryName(dir), depth + 1, 0)
				SetHyperTreeItemAttribute(0, index, #HyperTree_Font, fontSmall)
				index + 1
			EndIf
		Wend
		FinishDirectory(dir)
	EndIf
EndProcedure

HyperTreeGadget(0, 5, 30, 290, 360, font1)

ScanPath("C:\")

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      End
    Case #PB_Event_Gadget
      HyperTreeEvent(0)
     
      If EventGadget()=1
       
        RemoveHyperTreeItem(0, GetHyperTreeState(0))
      EndIf
  EndSelect
ForEver

Re: HyperTreeGadget

Verfasst: 30.05.2012 12:05
von Lambda
@RSBasic

Seltsam :D bei mir tritt keins von deinen genannten Effekten auf. Und CheckBoxen können mit Feldern gemacht werden.

Re: HyperTreeGadget

Verfasst: 30.05.2012 18:35
von RSBasic
@cOoki3druqs
Ich hab dein Code jetzt nochmal getestet. Das Problem ist jetzt nicht mehr vorhanden. Warum heute früh das nicht richtig ging, keine Ahnung.
Sieht gut aus. :allright:

Re: HyperTreeGadget

Verfasst: 30.05.2012 19:28
von Lambda
Beruhigend :D danke.

Bin gerade an den Scrollbars. Leider hab ich mich wo verrechnet, so wird die ScrollBar Position nicht richtig in die reale umgerechnet. (sichtbar erst bei mehreren Items wie hier -> >90)

Code: Alles auswählen

; HyperTreeGadget.pb
;
; Version: 1.0

; Constants
#HyperTree_Selected       =       0 ; Is Item selected? (#True/#False)
#HyperTree_Node           =       1 ; Is Item a Node? (#True/False)


#HyperTree_Font           =       2 ; Set Item Font. (FontNumber)

; Flags
#HyperTree_MultiSelect = 1<<0
#HyperTree_FullRowSelect = 1<<1



Structure HYPERTREE_FIELD_INFO
  img.i
  w.i
  h.i
EndStructure

Structure HYPERTREE_ITEM_INFO
  txt.s
  pos.i
  sel.i
  lvl.i
  exp.i
  node.i
  rect.RECT
 
  h.i
 
  cBkgnd.i
  cTitle.i
  cBoxSel.i
  cBoxSelHi.i
  cBoxBkgnd.i
  cBoxBrd.i
 
  gdata.i
  font.i
 
  List field.HYPERTREE_FIELD_INFO()
EndStructure

Structure HYPERTREE_INFO
  id.l
  flags.l
 
  ml.i
  pw.i
  ph.i
  sx.i
  sy.i
  sw.i
  rsx.i
  rsy.i
  sh.i
  bx.i
  by.i
  scroll.i
  scrollx.i
  indent.i
  spacing.i
  font.i
 
  cBkgnd.i
  cDkBrd.i
  cBrd.i
 
  List item.HYPERTREE_ITEM_INFO()
EndStructure


Procedure HyperTreeEvent(GadgetID.i)
  Protected *g.HYPERTREE_INFO = GetGadgetData(GadgetID)
  Protected w.i, h.i, mx.i, my.i
  Protected ch.i=4, cw.i=4, ci.i= *g\indent, cl.i, exp.i=#True, sel.i=-1, xw.i
 
  mx = GetGadgetAttribute(GadgetID, #PB_Canvas_MouseX)
  my = GetGadgetAttribute(GadgetID, #PB_Canvas_MouseY)
 
  Select EventType()
    Case #PB_EventType_LeftButtonDown
      *g\ml=#True
      *g\bx=mx-*g\sx
      *g\by=my-*g\sy
    Case #PB_EventType_LeftButtonUp
      *g\scroll=#False
      *g\scrollx=#False
      *g\ml=#False
  EndSelect
 
 
  StartDrawing(CanvasOutput(GadgetID))
    w=OutputWidth()
    h=OutputHeight()
   
    Box(0, 0, w, h, *g\cBkgnd)
   
    ; Items
    With *g\item()
      ForEach *g\item()
        If \lvl<=expl
          exp=#True
        ElseIf \lvl>expl And exp=#False
          Continue
        EndIf
       
        If \lvl>cl And exp=#True
          ; Stop stop stoooop! We're a Child now so go back and tell your Parent!
          PreviousElement(*g\item())
          \node=#True
          DrawingMode(#PB_2DDrawing_Default)
          Box(-*g\rsx+\rect\left-12, -*g\sy+\rect\top+\h/2-5, 10, 10, \cBoxBkgnd)
          DrawingMode(#PB_2DDrawing_Outlined)
          Box(-*g\rsx+\rect\left-12, -*g\rsy+\rect\top+\h/2-5, 10, 10, \cBoxBrd)
         
          If \exp=#False
            LineXY(-*g\rsx+\rect\left-10, -*g\rsy+\rect\top+\h/2, -*g\rsx+\rect\left-5, -*g\rsy+\rect\top+\h/2, \cBoxBrd)
            LineXY(-*g\rsx+\rect\left-8, -*g\rsy+\rect\top+\h/2-3, -*g\rsx+\rect\left-8, -*g\rsy+\rect\top+\h/2+2, \cBoxBrd)
          Else
            LineXY(-*g\rsx+\rect\left-10, -*g\rsy+\rect\top+\h/2, -*g\rsx+\rect\left-5, -*g\rsy+\rect\top+\h/2, \cBoxBrd)
          EndIf
         
            If exp=#True
              exp=\exp
              expl=\lvl
            EndIf
           
            NextElement(*g\item())
           
          cl=\lvl
         
          If exp=#False
            Continue
          EndIf
        ElseIf \lvl<cl
          exp=#True
        EndIf
       
       
        ; Check Item
       
        xw = 0
        cl = \lvl
        \rect\left=*g\indent*(\lvl+1)
        \rect\top=ch
        \rect\bottom=ch+\h
        \rect\right=\rect\left+TextWidth(\txt)
       
       
        If EventType()=#PB_EventType_LeftClick And EventGadget()=GadgetID
          If mx>\rect\left-12-*g\rsx And mx<\rect\left-*g\rsx And my>\rect\top-*g\rsy And my<\rect\bottom-*g\rsy And \node=#True
            \exp=\exp!1
          ElseIf mx>\rect\left-*g\rsx And mx<\rect\right-*g\rsx And my>\rect\top-*g\rsy And my<\rect\bottom-*g\rsy
            \sel=#True
          ElseIf Not *g\flags & #HyperTree_MultiSelect And GetAsyncKeyState_(#VK_CONTROL)=#False
            \sel=#False
          EndIf
        EndIf
       
       
       
        DrawingMode(#PB_2DDrawing_Default|#PB_2DDrawing_Transparent)
        Box(-*g\rsx+\rect\left, -*g\rsy+ch, TextWidth(\txt), ch+\h, \cBoxBkgnd)
        If \sel
          RoundBox(-*g\rsx+\rect\left, -*g\rsy+\rect\top, w-\rect\left-4, \h, 3, 3, \cBoxSel)
        EndIf
       
        If mx>\rect\left-*g\rsx And mx<\rect\right-*g\rsx And my>\rect\top-*g\rsy And my<\rect\bottom-*g\rsy
          RoundBox(-*g\rsx+\rect\left, -*g\rsy+\rect\top, w-\rect\left-4, \h, 3, 3, \cBoxSelHi)
        EndIf
       
        ; Fields
        ForEach *g\item()\field()
          If \field()\img<>-1
            DrawingMode(#PB_2DDrawing_AlphaBlend)
            DrawImage(ImageID(\field()\img), -*g\rsx+xw+\rect\left, -*g\rsy+\rect\top, \field()\w, \field()\h)
          EndIf
          xw+\field()\w
        Next
       
        DrawingMode(#PB_2DDrawing_Default|#PB_2DDrawing_Transparent)
        DrawingFont(FontID(\font))
        DrawText(-*g\rsx+xw+\rect\left+2, -*g\rsy+ch+2, \txt, \cTitle)
        xw+TextWidth(\txt)
       
        DrawingMode(#PB_2DDrawing_Outlined)
        Box(1, 1, w-2, h-2, *g\cDkBrd)
        Box(0, 0, w, h, *g\cBrd)
        DrawingMode(#PB_2DDrawing_Default)
       
        ch+\h+*g\spacing
       
        If cw<\rect\left+xw
          cw=\rect\left
        EndIf
      Next
     
      ; ScrollBar
      *g\ph=ch
      *g\pw=cw
     
      If *g\ph>h
        *g\sh=h-(h/100*((h/100)*(*g\ph))/100)
        Debug *g\sh
        If ((*g\ml=#True And mx>w-22 And my>*g\sy And my<*g\sy+*g\sh) Or *g\scroll=#True) And my>*g\by And my<h-(*g\sh-*g\by)-4
          If *g\scroll=#False
            *g\scroll=#True
          EndIf
         
          *g\sy=(my-*g\by)
          *g\rsy=(*g\sy)*(*g\ph/(h-*g\sh))
        ElseIf my<*g\by And *g\scroll=#True
          *g\sy=0
          *g\rsy=*g\ph/100**g\sy
        ElseIf my>h-(*g\sh-*g\by)-4 And *g\scroll=#True
          *g\sy=h-(*g\sh)-4
          *g\rsy=*g\ph-h
        EndIf
       
       
        Box(w-22, 2, 20, h-4, #Gray)
        Box(w-21, 2+*g\sy, 19, *g\sh, RGB($F3,$F3,$F3))
      EndIf
     
      ; If *g\pw<w
        ; *g\sw=w-24-((w-24)/100*(((w-24)/100)**g\pw)/100)-24
        ; If ((*g\ml=#True And mx>2 And my>h-22 And mx<w-24) Or *g\scrollx=#True) And mx>*g\bx And mx<w-(*g\sw-*g\bx)
          ; If *g\scrollx=#False
            ; *g\scrollx=#True
          ; EndIf
          ;
          ; *g\sx=(mx-*g\bx)
          ; *g\rsx=*g\pw/*g\sw**g\sx
        ; ElseIf mx<*g\bx And *g\scrollx=#True
          ; *g\sx=0
          ; *g\rsx=*g\pw/100**g\sx
        ; ElseIf mx>w-(*g\sw-*g\bx) And *g\scrollx=#True
          ; *g\sx=w-(*g\sw)
          ; *g\rsx=*g\pw-w
        ; EndIf
        ;
        ;
        ; Box(2, h-22, w-24, 20, #Gray)
        ; Box(2+*g\sx, h-21, *g\sw-25, 19, RGB($F3,$F3,$F3))
      ; EndIf
     
    EndWith
  StopDrawing()
EndProcedure


Procedure HyperTreeGadget(GadgetID.i, x.i, y.i, Width.i, Height.i, font.i, flags.l=#Null)
  Protected *g.HYPERTREE_INFO=AllocateMemory(SizeOf(HYPERTREE_INFO))
  If GadgetID=#PB_Any
      result = CanvasGadget(#PB_Any, x, y, Width, Height)
  Else
    result = GadgetID
    CanvasGadget(GadgetID, x, y, Width, Height)
  EndIf
 
 
 
  InitializeStructure(*g, HYPERTREE_INFO)
 
  With *g
    \id = result
    \flags = flags
    \cBkgnd = GetSysColor_(#COLOR_WINDOW)
    \cBrd = GetSysColor_(#COLOR_3DLIGHT)
    \cDkBrd = GetSysColor_(#COLOR_3DSHADOW)
    \indent = 32
    \spacing = 0
    \font = font
  EndWith
 
  SetGadgetData(result, *g)
  HyperTreeEvent(GadgetID)
  ProcedureReturn result
EndProcedure

Procedure AddHyperTreeItem(GadgetID.i, index.i, text.s, level.i=0, redraw=#True, expanded.i=#True, h.i=20)
  Protected *g.HYPERTREE_INFO = GetGadgetData(GadgetID)
 
  AddElement(*g\item())
  With *g\item()
    \txt = text
    \pos = index
    \lvl = level
    \exp = expanded
   
    \h = h
    \cBkgnd = GetSysColor_(#COLOR_WINDOW)
    \cTitle = GetSysColor_(#COLOR_BTNTEXT)
    \cBoxBkgnd = GetSysColor_(#COLOR_WINDOW)
    \cBoxBrd = GetSysColor_(#COLOR_3DDKSHADOW)
    \cBoxSel = RGB($DF,$E3,$F2)
    \cBoxSelHi = RGB($EE,$F3,$F9)
   
    \font = *g\font
  EndWith
  If redraw=#True
    HyperTreeEvent(GadgetID)
  EndIf
EndProcedure

Procedure RemoveHyperTreeItem(GadgetID.i, index.i)
  Protected *g.HYPERTREE_INFO = GetGadgetData(GadgetID)
  Protected expl.i, c.i
 
  If index>-1 And index<=ListSize(*g\item())-1
  With *g\item()
    SelectElement(*g\item(), index)
    expl=\lvl
    DeleteElement(*g\item())
    If ListSize(*g\item())>0
    NextElement(*g\item())
    While \lvl>expl And index<ListSize(*g\item())-1
      DeleteElement(*g\item())
      NextElement(*g\item())
      c+1
    Wend
  EndWith
  EndIf
  HyperTreeEvent(GadgetID)
EndIf
EndProcedure

Procedure GetHyperTreeState(GadgetID.i)
  Protected *g.HYPERTREE_INFO = GetGadgetData(GadgetID)
 
  With *g\item()
    ForEach *g\item()
      If \sel=#True
        ProcedureReturn ListIndex(*g\item())
      EndIf
    Next
   
    ProcedureReturn -1
   
  EndWith
EndProcedure

Procedure AddHyperTreeItemField(GadgetID.i, index.i, w.i, h.i, img.i=-1, redraw=#True)
  Protected *g.HYPERTREE_INFO = GetGadgetData(GadgetID)
 
  With *g\item()\field()
    SelectElement(*g\item(), index)
    AddElement(*g\item()\field())
    \w = w
    \h = h
    \img = img
  EndWith
  If redraw=#True
    HyperTreeEvent(GadgetID)
  EndIf
 
EndProcedure

Procedure CountHyperTreeItems(GadgetID.i)
  Protected *g.HYPERTREE_INFO = GetGadgetData(GadgetID)
  ProcedureReturn ListSize(*g\item())
EndProcedure

Procedure GetHyperTreeItemAttribute(GadgetID.i, index.i, attribute.i)
  Protected *g.HYPERTREE_INFO = GetGadgetData(GadgetID)
 
  With *g\item()
    SelectElement(*g\item(), index)
    Select attribute
      Case #HyperTree_Selected
        ProcedureReturn \sel
      Case #HyperTree_Node
        ProcedureReturn \node
    EndSelect
  EndWith
 
EndProcedure

Procedure SetHyperTreeItemAttribute(GadgetID.i, index.i, attribute.i, value.i)
  Protected *g.HYPERTREE_INFO = GetGadgetData(GadgetID)
 
  With *g\item()
    SelectElement(*g\item(), index)
    Select attribute
      Case #HyperTree_Font
        \font = value
    EndSelect
  EndWith
 
EndProcedure

Procedure.s GetHyperTreeItemText(GadgetID.i, index.i)
  Protected *g.HYPERTREE_INFO = GetGadgetData(GadgetID)
 
  With *g\item()
    SelectElement(*g\item(), index)
        ProcedureReturn \txt
  EndWith
 
EndProcedure

Procedure SetHyperTreeItemText(GadgetID.i, index.i, text.s)
  Protected *g.HYPERTREE_INFO = GetGadgetData(GadgetID)
 
  With *g\item()
    SelectElement(*g\item(), index)
    \txt = text
  EndWith
 
  HyperTreeEvent(GadgetID)
EndProcedure

;- Example
UsePNGImageDecoder()


font1 = LoadFont(#PB_Any, "arial", 8, #PB_Font_HighQuality)
font2 = LoadFont(#PB_Any, "comic sans ms", 12, #PB_Font_Bold)

image1 = CreateImage(#PB_Any, 20,20,32|#PB_Image_Transparent)
StartDrawing(ImageOutput(image1))
  DrawingMode(#PB_2DDrawing_AlphaBlend|#PB_2DDrawing_AlphaClip)
  Circle(8,8,6,RGBA(170,200,240,200))
StopDrawing()

image2 = CreateImage(#PB_Any, 20,20,32|#PB_Image_Transparent)
StartDrawing(ImageOutput(image2))
  DrawingMode(#PB_2DDrawing_AlphaBlend|#PB_2DDrawing_AlphaClip)
  Circle(8,8,6,RGBA(170,200,140,200))
StopDrawing()

OpenWindow(0, 0, 0, 300, 400, "HyperTreeGadget", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)

ButtonGadget(2, 5, 5, 70, 20, "Add")
ButtonGadget(1, 80, 5, 70, 20, "Remove")
HyperTreeGadget(0, 5, 30, 290, 360, font1)
AddHyperTreeItem(0, 0, "test0", 0, 1,1)
AddHyperTreeItem(0, 0, "test1", 1)
AddHyperTreeItem(0, 0, "test2", 1, 1,1)
AddHyperTreeItem(0, 0, "test2", 2, 1,1)
AddHyperTreeItem(0, 0, "test2", 3, 1,1)
AddHyperTreeItem(0, 0, "test2", 4, 1,1)
AddHyperTreeItem(0, 0, "test2", 5, 1,1)
AddHyperTreeItem(0, 0, "test2", 6, 1,1)
AddHyperTreeItem(0, 0, "test2", 7, 1,1)
AddHyperTreeItem(0, 0, "test2", 8, 1,1)
AddHyperTreeItem(0, 0, "test3", 2, 1,0, 54) ; A bit higher for the new Font.
AddHyperTreeItem(0, 0, "test4", 2)
AddHyperTreeItem(0, 0, "test5", 1)
AddHyperTreeItem(0, 0, "test6", 0)

Define c.i
For c=7 To 90
  AddHyperTreeItem(0, 0, "test"+Str(c), 0, #False) ; Important! Don't redraw until finished, then it's very fast.
Next
HyperTreeEvent(0)



; Set Font of Item3
SetHyperTreeItemAttribute(0, 3, #HyperTree_Font, font2)

; Add extra Fields to Item5
AddHyperTreeItemField(0, 5, 20, 20, image1)
AddHyperTreeItemField(0, 5, 20, 20, image2)
; Add extra Fields to Item2
AddHyperTreeItemField(0, 2, 20, 20, image1)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      End
    Case #PB_Event_Gadget
      HyperTreeEvent(0)
     
      Select EventGadget()
        Case 1
          RemoveHyperTreeItem(0, GetHyperTreeState(0))
        Case 2
          AddHyperTreeItem(0, 0, "test", 0)
      EndSelect
  EndSelect
ForEver

Re: HyperTreeGadget

Verfasst: 30.05.2012 19:35
von RSBasic
@cOoki3druqs
Kannst du das eigentlich nicht in einem ScrollAreaGadget machen?
Also wenn die gezeichnete Liste größer ist, als die Höhe des CanvasGadgets, dann brauchst du ja nur die Inline-Höhe (Scrollbereich) des ScrollAreaGadgets zu erhöhen.
Ginge das oder würde das zu doll flackern?

Re: HyperTreeGadget

Verfasst: 30.05.2012 19:59
von Lambda
Das ginge natrülich, aber ich halte nichts von solchen Zombie Gadgets :D . Zudem müsste das Canvas dann immer auf die real benötigte größe skaliert sein. So ist es Speicher schonend und einfacher zu handhaben. Die Scrollbar ist auch erstmal Platzhalter, die kann man dann mit 3 Grafikstücken skinnen.

:| Problem: ca Zeile 218

Code: Alles auswählen

*g\rsy=((*g\sy)*((*g\ph)/h))
rsy - ist die reale(hochgerechnete) Position
sy - ist die Position der ScrollBar(obere Kante)
ph - ist die benötigte reale Seitenlänge
h - ist die höhe des Gadgets
sh - die höhe der ScrollBar

Die Ansicht muss also entsprechend der ScrollBar Position zur Seitenlänge verschoben werden, allerdings muss die Scrollbar höhe mit hochgerechnet werden da die Seite ja am Ende stehn muss wenn die ScrollBar ganz unten ist, aber sy wegen sh nicht ganz unten.

Re: HyperTreeGadget

Verfasst: 30.05.2012 20:47
von Lambda
Mit paar Optimierungen auch bei 10.000+ Items noch recht schnell. Wobei es eher für kleinere Einsatzgebiete gedacht ist. (verwende es final in einer Grafiksoftware)

Code: Alles auswählen

; HyperTreeGadget.pb
;
; Version: 1.0

; Constants
#HyperTree_Selected       =       0 ; Is Item selected? (#True/#False)
#HyperTree_Node           =       1 ; Is Item a Node? (#True/False)


#HyperTree_Font           =       2 ; Set Item Font. (FontNumber)

; Flags
#HyperTree_MultiSelect = 1<<0
#HyperTree_FullRowSelect = 1<<1



Structure HYPERTREE_FIELD_INFO
  img.i
  w.i
  h.i
EndStructure

Structure HYPERTREE_ITEM_INFO
  txt.s
  pos.i
  sel.i
  lvl.i
  exp.i
  node.i
  rect.RECT
  
  h.i
  
  cBkgnd.i
  cTitle.i
  cBoxSel.i
  cBoxSelHi.i
  cBoxBkgnd.i
  cBoxBrd.i
  
  gdata.i
  font.i
  
  List field.HYPERTREE_FIELD_INFO()
EndStructure

Structure HYPERTREE_INFO
  id.l
  flags.l
  
  ml.i
  pw.f
  ph.f
  sx.f
  sy.f
  sw.f
  rsx.f
  rsy.f
  sh.f
  bx.i
  by.i
  scroll.i
  scrollx.i
  indent.i
  spacing.i
  font.i
  
  cBkgnd.i
  cDkBrd.i
  cBrd.i
  
  List item.HYPERTREE_ITEM_INFO()
EndStructure


Procedure HyperTreeEvent(GadgetID.i)
  Protected *g.HYPERTREE_INFO = GetGadgetData(GadgetID)
  Protected w.i, h.i, mx.i, my.i
  Protected ch.i=4, cw.i=4, ci.i= *g\indent, cl.i, exp.i=#True, sel.i=-1, xw.i
  
  mx = GetGadgetAttribute(GadgetID, #PB_Canvas_MouseX)
  my = GetGadgetAttribute(GadgetID, #PB_Canvas_MouseY)
  
  Select EventType()
    Case #PB_EventType_LeftButtonDown
      *g\ml=#True
      *g\bx=mx-*g\sx
      *g\by=my-*g\sy
    Case #PB_EventType_LeftButtonUp
      *g\scroll=#False
      *g\scrollx=#False
      *g\ml=#False
  EndSelect
  
  
  StartDrawing(CanvasOutput(GadgetID))
    w=OutputWidth()
    h=OutputHeight()
    
    Box(0, 0, w, h, *g\cBkgnd)
    
    ; Items
    With *g\item()
      ForEach *g\item()
        If \lvl<=expl
          exp=#True
        ElseIf \lvl>expl And exp=#False
          Continue
        EndIf
        
        If \lvl>cl And exp=#True
          ; Stop stop stoooop! We're a Child now so go back and tell your Parent!
          PreviousElement(*g\item())
          \node=#True
          DrawingMode(#PB_2DDrawing_Default)
          Box(-*g\rsx+\rect\left-12, -*g\sy+\rect\top+\h/2-5, 10, 10, \cBoxBkgnd)
          DrawingMode(#PB_2DDrawing_Outlined)
          Box(-*g\rsx+\rect\left-12, -*g\rsy+\rect\top+\h/2-5, 10, 10, \cBoxBrd)
          
          If \exp=#False
            LineXY(-*g\rsx+\rect\left-10, -*g\rsy+\rect\top+\h/2, -*g\rsx+\rect\left-5, -*g\rsy+\rect\top+\h/2, \cBoxBrd)
            LineXY(-*g\rsx+\rect\left-8, -*g\rsy+\rect\top+\h/2-3, -*g\rsx+\rect\left-8, -*g\rsy+\rect\top+\h/2+2, \cBoxBrd)
          Else
            LineXY(-*g\rsx+\rect\left-10, -*g\rsy+\rect\top+\h/2, -*g\rsx+\rect\left-5, -*g\rsy+\rect\top+\h/2, \cBoxBrd)
          EndIf
          
            If exp=#True
              exp=\exp
              expl=\lvl
            EndIf
            
            NextElement(*g\item())
            
          cl=\lvl
          
          If exp=#False
            Continue
          EndIf
        ElseIf \lvl<cl
          exp=#True
        EndIf
        
        
        ; Check Item
        
        xw = 0
        cl = \lvl
        \rect\left=*g\indent*(\lvl+1)
        \rect\top=ch
        \rect\bottom=ch+\h
        \rect\right=\rect\left+TextWidth(\txt)
        
        If \rect\bottom-*g\rsy>0 And \rect\top-*g\rsy<h ;/
        If EventType()=#PB_EventType_LeftClick And EventGadget()=GadgetID
          If mx>\rect\left-12-*g\rsx And mx<\rect\left-*g\rsx And my>\rect\top-*g\rsy And my<\rect\bottom-*g\rsy And \node=#True
            \exp=\exp!1
          ElseIf mx>\rect\left-*g\rsx And mx<\rect\right-*g\rsx And my>\rect\top-*g\rsy And my<\rect\bottom-*g\rsy
            \sel=#True
          ElseIf Not *g\flags & #HyperTree_MultiSelect And GetAsyncKeyState_(#VK_CONTROL)=#False
            \sel=#False
          EndIf
        EndIf
      EndIf
      
      
      If \rect\bottom-*g\rsy>0 And \rect\top-*g\rsy<h ;/
        DrawingMode(#PB_2DDrawing_Default|#PB_2DDrawing_Transparent)
        Box(-*g\rsx+\rect\left, -*g\rsy+ch, TextWidth(\txt), ch+\h, \cBoxBkgnd)
        If \sel
          RoundBox(-*g\rsx+\rect\left, -*g\rsy+\rect\top, w-\rect\left-4, \h, 3, 3, \cBoxSel)
        EndIf
        
        If mx>\rect\left-*g\rsx And mx<\rect\right-*g\rsx And my>\rect\top-*g\rsy And my<\rect\bottom-*g\rsy
          RoundBox(-*g\rsx+\rect\left, -*g\rsy+\rect\top, w-\rect\left-4, \h, 3, 3, \cBoxSelHi)
        EndIf
        
      EndIf  ;/
        
        ; Fields
        ForEach *g\item()\field()
          If \field()\img<>-1
            DrawingMode(#PB_2DDrawing_AlphaBlend)
            DrawImage(ImageID(\field()\img), -*g\rsx+xw+\rect\left, -*g\rsy+\rect\top, \field()\w, \field()\h)
          EndIf
          xw+\field()\w
        Next
        
        If \rect\bottom-*g\rsy>0 And \rect\top-*g\rsy<h ;/
        DrawingMode(#PB_2DDrawing_Default|#PB_2DDrawing_Transparent)
        DrawingFont(FontID(\font))
        DrawText(-*g\rsx+xw+\rect\left+2, -*g\rsy+ch+2, \txt, \cTitle)
        xw+TextWidth(\txt)
        
        DrawingMode(#PB_2DDrawing_Outlined)
        Box(1, 1, w-2, h-2, *g\cDkBrd)
        Box(0, 0, w, h, *g\cBrd)
        DrawingMode(#PB_2DDrawing_Default)
        EndIf ;/
      
        ch+\h+*g\spacing
        
        If cw<\rect\left+xw
          cw=\rect\left
        EndIf
      Next
      
      ; ScrollBar
      *g\ph=ch
      *g\pw=cw
      
      If *g\ph>h
        *g\sh=h-(h/100*((h/100)*(*g\ph))/100)
        If *g\sh<10
          *g\sh=10
        EndIf
        
        If ((*g\ml=#True And mx>w-22 And my>*g\sy And my<*g\sy+*g\sh) Or *g\scroll=#True) And my>*g\by And my<h-(*g\sh-*g\by)-4
          If *g\scroll=#False
            *g\scroll=#True
          EndIf
          
          *g\sy=(my-*g\by)
          *g\rsy=((*g\sy)*((*g\ph)/(h-4)))+(((100/((h-4)-*g\sh))* (*g\sy))     * (*g\sh/100))
          
        ElseIf my<*g\by And *g\scroll=#True
          *g\sy=0
          *g\rsy=*g\ph/100**g\sy
        ElseIf my>h-(*g\sh-*g\by)-4 And *g\scroll=#True
          *g\sy=h-(*g\sh)-4
          *g\rsy=*g\ph-h
        EndIf
        
        
        Box(w-22, 2, 20, h-4, #Gray)
        Box(w-21, 2+*g\sy, 19, *g\sh, RGB($F3,$F3,$F3))
      EndIf
      
      If *g\pw<w
        *g\sw=w-24-((w-24)/100*(((w-24)/100)**g\pw)/100)-24
        If ((*g\ml=#True And mx>2 And my>h-22 And mx<w-24) Or *g\scrollx=#True) And mx>*g\bx And mx<w-(*g\sw-*g\bx)
          If *g\scrollx=#False
            *g\scrollx=#True
          EndIf
          
          *g\sx=(mx-*g\bx)
          *g\rsx=*g\pw/*g\sw**g\sx
        ElseIf mx<*g\bx And *g\scrollx=#True
          *g\sx=0
          *g\rsx=*g\pw/100**g\sx
        ElseIf mx>w-(*g\sw-*g\bx) And *g\scrollx=#True
          *g\sx=w-(*g\sw)
          *g\rsx=*g\pw-w
        EndIf
        
        
        Box(2, h-22, w-24, 20, #Gray)
        Box(2+*g\sx, h-21, *g\sw-25, 19, RGB($F3,$F3,$F3))
      EndIf
      
    EndWith
  StopDrawing()
EndProcedure


Procedure HyperTreeGadget(GadgetID.i, x.i, y.i, Width.i, Height.i, font.i, flags.l=#Null)
  Protected *g.HYPERTREE_INFO=AllocateMemory(SizeOf(HYPERTREE_INFO))
  If GadgetID=#PB_Any
      result = CanvasGadget(#PB_Any, x, y, Width, Height)
  Else
    result = GadgetID
    CanvasGadget(GadgetID, x, y, Width, Height)
  EndIf
  
  
  
  InitializeStructure(*g, HYPERTREE_INFO)
  
  With *g
    \id = result
    \flags = flags
    \cBkgnd = GetSysColor_(#COLOR_WINDOW)
    \cBrd = GetSysColor_(#COLOR_3DLIGHT)
    \cDkBrd = GetSysColor_(#COLOR_3DSHADOW)
    \indent = 32
    \spacing = 0
    \font = font
  EndWith
  
  SetGadgetData(result, *g)
  HyperTreeEvent(GadgetID)
  ProcedureReturn result
EndProcedure

Procedure AddHyperTreeItem(GadgetID.i, index.i, text.s, level.i=0, redraw=#True, expanded.i=#True, h.i=20)
  Protected *g.HYPERTREE_INFO = GetGadgetData(GadgetID)
  
  AddElement(*g\item())
  With *g\item()
    \txt = text
    \pos = index
    \lvl = level
    \exp = expanded
    
    \h = h
    \cBkgnd = GetSysColor_(#COLOR_WINDOW)
    \cTitle = GetSysColor_(#COLOR_BTNTEXT)
    \cBoxBkgnd = GetSysColor_(#COLOR_WINDOW)
    \cBoxBrd = GetSysColor_(#COLOR_3DDKSHADOW)
    \cBoxSel = RGB($DF,$E3,$F2)
    \cBoxSelHi = RGB($EE,$F3,$F9)
    
    \font = *g\font
  EndWith
  If redraw=#True
    HyperTreeEvent(GadgetID)
  EndIf
EndProcedure

Procedure RemoveHyperTreeItem(GadgetID.i, index.i)
  Protected *g.HYPERTREE_INFO = GetGadgetData(GadgetID)
  Protected expl.i, c.i
  
  If index>-1 And index<=ListSize(*g\item())-1
  With *g\item()
    SelectElement(*g\item(), index)
    expl=\lvl
    DeleteElement(*g\item())
    If ListSize(*g\item())>0
    NextElement(*g\item())
    While \lvl>expl And index<ListSize(*g\item())-1
      DeleteElement(*g\item())
      NextElement(*g\item())
      c+1
    Wend
  EndWith
  EndIf
  HyperTreeEvent(GadgetID)
EndIf
EndProcedure

Procedure GetHyperTreeState(GadgetID.i)
  Protected *g.HYPERTREE_INFO = GetGadgetData(GadgetID)
  
  With *g\item()
    ForEach *g\item()
      If \sel=#True
        ProcedureReturn ListIndex(*g\item())
      EndIf
    Next
    
    ProcedureReturn -1
    
  EndWith
EndProcedure

Procedure AddHyperTreeItemField(GadgetID.i, index.i, w.i, h.i, img.i=-1, redraw=#True)
  Protected *g.HYPERTREE_INFO = GetGadgetData(GadgetID)
  
  With *g\item()\field()
    SelectElement(*g\item(), index)
    AddElement(*g\item()\field())
    \w = w
    \h = h
    \img = img
  EndWith
  If redraw=#True
    HyperTreeEvent(GadgetID)
  EndIf
  
EndProcedure

Procedure CountHyperTreeItems(GadgetID.i)
  Protected *g.HYPERTREE_INFO = GetGadgetData(GadgetID)
  ProcedureReturn ListSize(*g\item())
EndProcedure

Procedure GetHyperTreeItemAttribute(GadgetID.i, index.i, attribute.i)
  Protected *g.HYPERTREE_INFO = GetGadgetData(GadgetID)
  
  With *g\item()
    SelectElement(*g\item(), index)
    Select attribute
      Case #HyperTree_Selected
        ProcedureReturn \sel
      Case #HyperTree_Node
        ProcedureReturn \node
    EndSelect
  EndWith
  
EndProcedure

Procedure SetHyperTreeItemAttribute(GadgetID.i, index.i, attribute.i, value.i)
  Protected *g.HYPERTREE_INFO = GetGadgetData(GadgetID)
  
  With *g\item()
    SelectElement(*g\item(), index)
    Select attribute
      Case #HyperTree_Font
        \font = value
    EndSelect
  EndWith
  
EndProcedure

Procedure.s GetHyperTreeItemText(GadgetID.i, index.i)
  Protected *g.HYPERTREE_INFO = GetGadgetData(GadgetID)
  
  With *g\item()
    SelectElement(*g\item(), index)
        ProcedureReturn \txt
  EndWith
  
EndProcedure

Procedure SetHyperTreeItemText(GadgetID.i, index.i, text.s)
  Protected *g.HYPERTREE_INFO = GetGadgetData(GadgetID)
  
  With *g\item()
    SelectElement(*g\item(), index)
    \txt = text
  EndWith
  
  HyperTreeEvent(GadgetID)
EndProcedure

;- Example
UsePNGImageDecoder()


font1 = LoadFont(#PB_Any, "arial", 8, #PB_Font_HighQuality)
font2 = LoadFont(#PB_Any, "comic sans ms", 12, #PB_Font_Bold)

image1 = CreateImage(#PB_Any, 20,20,32|#PB_Image_Transparent)
StartDrawing(ImageOutput(image1))
  DrawingMode(#PB_2DDrawing_AlphaBlend|#PB_2DDrawing_AlphaClip)
  Circle(8,8,6,RGBA(170,200,240,200))
StopDrawing()

image2 = CreateImage(#PB_Any, 20,20,32|#PB_Image_Transparent)
StartDrawing(ImageOutput(image2))
  DrawingMode(#PB_2DDrawing_AlphaBlend|#PB_2DDrawing_AlphaClip)
  Circle(8,8,6,RGBA(170,200,140,200))
StopDrawing()

OpenWindow(0, 0, 0, 300, 400, "HyperTreeGadget", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)

ButtonGadget(2, 5, 5, 70, 20, "Add")
ButtonGadget(1, 80, 5, 70, 20, "Remove")
HyperTreeGadget(0, 5, 30, 290, 360, font1)
AddHyperTreeItem(0, 0, "test0", 0, 1,1)
AddHyperTreeItem(0, 0, "test1", 1)
AddHyperTreeItem(0, 0, "test2", 1, 1,1)
AddHyperTreeItem(0, 0, "test2", 2, 1,1)
AddHyperTreeItem(0, 0, "test2", 3, 1,1)
AddHyperTreeItem(0, 0, "test2", 4, 1,1)
AddHyperTreeItem(0, 0, "test2", 5, 1,1)
AddHyperTreeItem(0, 0, "test2", 6, 1,1)
AddHyperTreeItem(0, 0, "test2", 7, 1,1)
AddHyperTreeItem(0, 0, "test2", 8, 1,1)
AddHyperTreeItem(0, 0, "test3", 2, 1,0, 54) ; A bit higher for the new Font.
AddHyperTreeItem(0, 0, "test4", 2)
AddHyperTreeItem(0, 0, "test5", 1)
AddHyperTreeItem(0, 0, "test6", 0)

Define c.i
For c=7 To 10000
  AddHyperTreeItem(0, 0, "test"+Str(c), 1, #False) ; Important! Don't redraw until finished, then it's very fast.
Next
HyperTreeEvent(0)



; Set Font of Item3
SetHyperTreeItemAttribute(0, 3, #HyperTree_Font, font2)

; Add extra Fields to Item5
AddHyperTreeItemField(0, 5, 20, 20, image1) 
AddHyperTreeItemField(0, 5, 20, 20, image2) 
; Add extra Fields to Item2
AddHyperTreeItemField(0, 2, 20, 20, image1) 

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      End
    Case #PB_Event_Gadget
      HyperTreeEvent(0)
      
      Select EventGadget()
        Case 1
          RemoveHyperTreeItem(0, GetHyperTreeState(0))
        Case 2
          AddHyperTreeItem(0, 0, "test", 0)
      EndSelect
  EndSelect
ForEver

Re: HyperTreeGadget

Verfasst: 30.05.2012 21:12
von LuZiF3R
geile sache, aber hier noch nen kleiner bug,

wenn ich alles einklappe und in deinem Beispiel nach rechts scrolle, erscheint der Inhalt ein zweites mal, halt aber abgeschnitten