(erledigt) Types und Liste

Previous topic - Next topic

Quentin

Für sowas nimmt man sich normalerweise eine Manager-Klasse oder sowa in der Art.
Angenommen es gibt etliche GUI-Komponenten wie Textfeld, Eingabefeld, Listbox etc.
Diese könnte man in einen eigenen Typ (oder mehrere nach Bedarf) stecken

Code (glbasic) Select

TYPE TGuiElement
    name$
    ...
ENDTYPE


Ein Dialog wiederum kann 1..n Gui-Komponenten enthalten also z.B. so

Code (glbasic) Select

TYPE TDialog
    ....
    GuiElements as TGuiElement[]
   ....
ENDTYPE


im ganzen Programm kann man ja 1..n Dialog nutzen, wo man z.B. auch das Hauptfenster als Dialog betrachten könnte. Alle Dialog könnte man in einem GUI-Manager verwalten

z.B.
Code (glbasic) Select

TYPE TGuiManager
   ...
   dialogs as TDialog[]
   ....
ENDTYPE


Richtiges OOP haben wir ja leider/Gott sei Dank (je nach Standpunkt) in GLBasic nicht, aber mit dieser Art der Komposition könnte man es ggfs. auch lösen, denke ich.

backslider

Außer dass du vielleicht:
Code (glbasic) Select

//statt
GuiElements as TGuiElement[]

//lieber
GuiElements[] as TGuiElement

schreiben solltest. :)
Oder geht's auch andersrum?  :blink:

Quentin

ups ja, hast recht, habs nur einfach so hingeschrieben ohne Editor :)

Markus

Was ich wollte war doch nur eine Struktur mit einem leeren Array was dann Pointer sammelt.
Beim erzeugen einer Variable mit diesem Typ passiert doch sonst weiter gar nix.
Da gibt es doch noch gar keine Rekursion.
Vieleicht hab ich auch grad nur ein Pin im Kopf aber ich bin überzeugt das ich das nicht falsch gemacht habe.

@Quentin
TGuiElement möchte aber TGuiElemente haben
Dein Beispiel hat ja nur 3 Ebenen.

Quentin

so ganz kann ich dir nicht folgen. Worauf genau willst du hinaus.
In deinem Beispiel hast du eine rekursive Definition. Dem könnte man in deinem Beispiel nur dadurch entgehen, wenn man das Array mit den GUI-Elementen als statisch im Sinne von statischen C++-Klassenmembern definiert, was so in GLBasic imho nicht möglich ist.

Ausserdem bezweifle ich, dass der Eierlegende-Woll-Milch-Sau-TYPE wirklich sinnvoll ist.

Markus

@Quentin
irgendwie fehlt mir dann eine Listen Klasse die alles aufnehmen kann.

Type TName
A=0
S as List
EndType

Local A as TName
Local B as TName
A.S.Add(B)

[attachment deleted by admin]

Quentin

ähh genau das kannst du doch damit machen?
Hier mal ein Beispiel:

Code (glbasic) Select


// GUI-Elemente, z.B. Label, Eingabefeld, pushbutton
TYPE TGuiElement
x%
y%
name$
content$
ENDTYPE

// Ein Dialog kann 1..n Gui-Elemente enthalten
TYPE TDialog
x%
y%
name$
items[] AS TGuiElement
ENDTYPE


// für das Hauptprogram benötigt man einen "GUI-Manager"
TYPE TGuiManager
dialogs[] AS TDialog
ENDTYPE


// jetzt mal ein paar GUI-Elemnte anlegne
LOCAL label AS TGuiElement
LOCAL inputfield AS TGuiElement
LOCAL checkbox AS TGuiElement

label.x = 0
label.y = 0
label.name$ = "LABEL"
label.content$ = "Eingabe:"

inputfield.x = 10
inputfield.y = 0
inputfield.name$ = "INPUTFIELD"
inputfield.content$ = ""

checkbox.x = 0
checkbox.y = 10
checkbox.name$ = "CHECKBOX"
checkbox.content$ = "X"

// diese packen wir in einen Dialog
LOCAL dialog AS TDialog

dialog.x = 0
dialog.y = 0
dialog.name$ = "DIALOG"
DIMPUSH dialog.items[], label
DIMPUSH dialog.items[], inputfield
DIMPUSH dialog.items[], checkbox

//... ggfs. weitere Dialog


// alle Dialog packen wir in unseren "Gui-Manager"
LOCAL guimgr AS TGuiManager
DIMPUSH guimgr.dialogs[], dialog

LOCAL y

WHILE TRUE

FOREACH dia IN guimgr.dialogs[]
y = 0
FOREACH item IN dia.items[]
PRINT item.name$, 0, y
PRINT item.content$, 100, y
INC y, 20
NEXT
NEXT

SHOWSCREEN

WEND

Kitty Hello

Nein. Ein Member eines Types darf keinen Member seines Parents haben. Das wäre rekursiv und geht nicht.

Mach eine Liste von Ta in Tb und pack die da rein. Baumstruktur geht nur über den Umweg einer Indexliste.

Markus

@Quentin
also so meinte ich das,das es eine Hirachie gibt. Also ich kann ein Fenster auch in eine Textbox tun wenn ich möchte.
Was ich gemacht habe ist ein Universal Element was sich nur anders malt/darstellt.

Type TElement
A=0
L as List
EndType

Local A as TElement
Local B as TElement
Local C as TElement
Local D as TElement
Local E as TElement
A.L.Add(B)
B.L.Add(C)
  C.L.Add(D)
   D.L.Add(E)



[attachment deleted by admin]

Slydog

Great point 'kanonet' about the 'New' keyword missing from GLBasic, therefore recursive TYPEs can never be allowed!
Never thought about it that way! 
This is a problem as long as a TYPE instance automatically reserves memory for each of its members.

But, as others have been mentioning, you don't need recursive TYPEs.
Use the 'id', 'id_parent' concept, and you are good to go.

Code (glbasic) Select
TYPE TGui
  id%
  id_parent%
  x%, y%

  frames[] AS TGuiFrame
  buttons[] AS TGuiButton

  FUNCTION Set: x, y, parent_id%=-1
    self.id = GetNextId()
    self.id_parent = parent_id
    self.x = x
    self.y = y
    DIM self.frames[0]
    DIM self.buttons[0]
  ENDFUNCTION

  FUNCTION AddFrame%: x, y
    LOCAL frame AS TGuiFrame
    frame.Set(x, y, self.id)
    DIMPUSH self.frames[], frame
    RETURN frame.id
  ENDFUNCTION

  FUNCTION AddButton%: x, y
    LOCAL button AS TGuiButton
    buttonSet(x, y, self.id)
    DIMPUSH self.buttons[], button
    RETURN button.id
  ENDFUNCTION
ENDTYPE

TYPE TGuiFrame
  id%
  id_parent%
  x%, y%

  FUNCTION Set: x, y, parent_id%=-1
    self.id = GetNextId()
    self.id_parent = parent_id
    self.x = x
    self.y = y
  ENDFUNCTION
ENDTYPE

TYPE TGuiButton
  id%
  id_parent%
  x%, y%

  FUNCTION Set: x, y, parent_id%=-1
    self.id = GetNextId()
    self.id_parent = parent_id
    self.x = x
    self.y = y
  ENDFUNCTION
ENDTYPE

FUNCTION GetNextId%:  is_reset%=FALSE
  STATIC id%=0
  IF is_reset THEN id=0
  INC id
  RETURN id
ENDFUNCTION


This way you can have window hierarchies too. 
One window can be the parent of another window.
One control can have a parent that is NOT a window, but another control.

Code (glbasic) Select
LOCAL gui1 AS TGui
LOCAL gui2 AS TGui

gui1.Set(10, 10) // id=1 (from GetNextId), id_parent=-1 since not specified - Top Level
gui2.Set(20, 20, gui1.id) // id=2, id_parent=1 - Child of gui1

frame_id = gui1.AddFrame(30, 30) // id=3
gui1.AddButton(10, 10, frame_id) // id=4, id_parent=3 - Button is a child of a Frame

Not exactly as written, but the concept is there.
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]

Markus

@Kitty Hello
ja, hab das anders gelöst, mir fehlt einfach eine Liste wo ich alles rein werfen kann und die ich eben so mir ForEach durch laufen kann.
BlitzMax hat sowas.


Markus

@Slydog

yes i used a parend/child list now (but without id^^)

Main Test
Code (glbasic) Select
// --------------------------------- //
// Project: MRGUI
// Start: Thursday, April 19, 2012
// MR 19.04.2012
// IDE Version: 10.283

MainLoop()
END

FUNCTION MainLoop:

SYSTEMPOINTER TRUE

LOCAL Gui AS TConnect

LOCAL G AS TGui

LOCAL sp=1

LOCAL y=0

    G_CreateBG()

    LOCAL Begin AS TGui
LOCAL Window AS TGui=G.CreateWindow  (0, 0,100,100,"Dialog");y=y+5+sp
    Gui.Add(Begin,Window)

G=G.CreateLabel(1, y, 99, y+5,"Spielstände");y=y+5+sp
Gui.Add(Window,G)


LOCAL List1 AS TGui=G.CreateList    (1, y, 93, y+5*4,"List")
Gui.Add(Window,List1)

LOCAL Slider2 AS TGui=G.CreateSlider  (94, y, 99, y+5*4,"SliderY")
Gui.Add(Window,Slider2)

y=y+5*4+sp

LOCAL Slider1 AS TGui=G.CreateSlider  (1, y, 93, y+5,"SliderX");y=y+5+sp
Gui.Add(Window,Slider1)

LOCAL i
LOCAL ty=List1.py1-2.5
FOR i=0 TO 5

G=G.CreateOption(List1.px1+1 ,ty ,List1.px1+ 19,ty+5,i)
IF i=1 THEN G.valuei=1
Gui.Add(List1,G)
G=G.CreateLabel(List1.px1+20 ,ty ,List1.px1+ 79,ty+5,"Level "+i+" - 19.04.12 1"+i+":15")
Gui.Add(List1,G)
G=G.CreateButton(List1.px1+80 ,ty ,List1.px1+ 90,ty+5,"X")
Gui.Add(List1,G)
ty=ty+6
NEXT

LOCAL Button2 AS TGui=G.CreateButton  (1, y, 50, y+5,"Laden")
Gui.Add(Window,Button2)

LOCAL Button1 AS TGui=G.CreateButton  (51, y, 99, y+5,"Speichern als");y=y+5+sp
Gui.Add(Window,Button1)

G=G.CreateTextbox  (51, y, 99, y+5,"Level 3 - 21.04.2012 15:35");y=y+5+sp
G.focus=1
Gui.Add(Window,G)

;y=y+5+sp
G=G.CreateLabel(1, y, 99, y+5,"Einstellungen");y=y+5+sp
Gui.Add(Window,G)

LOCAL Frame1 AS TGui=G.CreateFrame   (1, y, 50, y+5*5,"Schwierigkeitsgrad")
Gui.Add(Window,Frame1)

G=G.CreateOption  (1+1,y+ 5, 49,y+ 5+5,"Einfach")
G.valuei=1
Gui.Add(Frame1,G)
G=G.CreateOption  (1+1,y+ 5+5+1, 49,y+ 5+5+1+5,"Normal")
Gui.Add(Frame1,G)
G=G.CreateOption  (1+1,y+ 5+5+1+5+1, 49,y+ 5+5+1+5+5+1,"Schwer")
G.enabled=FALSE
Gui.Add(Frame1,G)

LOCAL Frame2 AS TGui=G.CreateFrame   (51, y, 99, y+5*5,"Akustik")
Gui.Add(Window,Frame2)

G=G.CreateCheckbox(51+1, y+5, 99-1, y+5+5,"Töne")
G.valuei=1
Gui.Add(Frame2,G)

G=G.CreateCheckbox(51+1, y+5+5+1, 99-1, y+5+5+5+1,"Musik")
G.valuei=1
Gui.Add(Frame2,G)

y=y+5*5+sp

DEBUG "Connect Einträge=" + BOUNDS(G_HierarchyList[],0) +"\n"

REPEAT

//0=X - Geschwindigkeit
//1=Y - Geschwindigkeit
//2=Rad (1 auf, -1 ab)
//3=linke Maustaste
//4=rechte Maustaste
//5=mittlere Maustaste

LOCAL wheel=MOUSEAXIS(2)
LOCAL bm=MOUSEAXIS(5)
LOCAL mx,my,b1,b2

MOUSESTATE mx,my,b1,b2

LOCAL keyasc$ = INKEY$( )
LOCAL keycode = KEY(1) //ESC

LOCAL vx,vy,width,height

Gui.Draw(Begin)

//Gui.Update(mx,my,b1,b2,bm,wheel,keyasc$) //Keys & Mouse

SHOWSCREEN

UNTIL FALSE

ENDFUNCTION


GUI
Code (glbasic) Select
// --------------------------------- //
// Project: MRGUI
// Start: Thursday, April 19, 2012
// MR 19.04.2012
// IDE Version: 10.283

//For a Combobox use a Button and a List

CONSTANT G_Window  =1
CONSTANT G_Label    =2
CONSTANT G_Button  =3
CONSTANT G_Slider  =4
CONSTANT G_List    =5
CONSTANT G_Checkbox =6
CONSTANT G_Option  =7
CONSTANT G_Frame =8
CONSTANT G_Textbox  =9

CONSTANT bgsprite1=101
CONSTANT bgsprite2=102
CONSTANT bgsprite3=103

TYPE TConnect
Parent AS TGui
Child AS TGui

FUNCTION Add:ParentX AS TGui,ChildX AS TGui

self.Parent=ParentX
self.Child=ChildX
DIMPUSH G_HierarchyList[],self

ENDFUNCTION

FUNCTION Draw:Parent AS TGui

//DEBUG Parent.text$ + "\n"
LOCAL vx,vy,width,height
GETVIEWPORT vx,vy,width,height //merken

Parent.Draw()

LOCAL w,h

LOCAL C AS TConnect
FOREACH C IN G_HierarchyList[]
IF C.Parent = Parent
          Parent.ChangeViewPort(w,h)
C.Draw(C.Child)
ENDIF
NEXT

VIEWPORT vx,vy,width,height //wieder herstellen

ENDFUNCTION

ENDTYPE
GLOBAL G_HierarchyList[] AS TConnect

TYPE TGui
typ //label,textbox,...

px1 // % 0 bis 100 = breite
py1
px2
py2

x1
y1
x2
y2
text$
valuei //bei Textbox Cursor Pos.
valuefx# //bei Slider -1 bis 1
valuefy#
enabled
visible
focus //bei Eingabe

//SubList[] AS TGui <<< geht nicht ^^

FUNCTION Init: typ , x1 , y1 , x2 , y2 , text$

self.px1=x1
self.py1=y1
self.px2=x2
self.py2=y2

    G_ProcentToReal( x1,y1 , x1,y1 )
    G_ProcentToReal( x2,y2 , x2,y2 )

self.typ=typ
self.x1=x1
self.y1=y1
self.x2=x2
self.y2=y2
self.text$=text$
self.valuei=0
self.valuefx#=0.0
self.valuefy#=0.0
self.enabled=TRUE
self.visible=TRUE
self.focus=FALSE

ENDFUNCTION

FUNCTION ChangeViewPort: BYREF w,BYREF h


LOCAL x,y
x=self.x1
y=self.y1

w=(self.x2-self.x1)+1
h=(self.y2-self.y1)+1

IF self.y1=0 AND self.y2=0
VIEWPORT 0,0,-1,-1
ELSE
VIEWPORT x,y,w,h
ENDIF

ENDFUNCTION

FUNCTION TextWidth: tx$

  LOCAL sx,sy
  GETFONTSIZE sx,sy
  RETURN sx*LEN(tx$)

ENDFUNCTION

FUNCTION TextHeight:

  LOCAL sx,sy
  GETFONTSIZE sx,sy
  RETURN sy

ENDFUNCTION

FUNCTION Draw:

IF self.visible=TRUE

LOCAL vx,vy,width,height
GETVIEWPORT vx,vy,width,height //merken Element drüber

IF self.x1<vx THEN RETURN
IF self.x2>vx+width THEN RETURN

IF self.y1<vy THEN RETURN
IF self.y2>vy+height THEN RETURN

LOCAL w,h
ChangeViewPort(w,h)

LOCAL bgcolor=RGB(0,0,64)
IF self.enabled=FALSE
STRETCHSPRITE bgsprite3, 0, 0, w, h //AUS
ELSEIF self.focus<>0
STRETCHSPRITE bgsprite2, 0, 0, w, h //AN mit Focus
    ELSE
STRETCHSPRITE bgsprite1, 0, 0, w, h //AN Normal
ENDIF

//Rahmen
LOCAL ColorL
LOCAL ColorD
IF self.focus
ColorL=RGB(0,0,64)
ColorD=RGB(255,255,255)
ELSE
ColorL=RGB(255,255,255)
ColorD=RGB(0,0,64)
ENDIF

IF self.typ=G_Label
ELSE
DRAWLINE 0,0,w-1,0,ColorL //Oben
DRAWLINE 0,0,0,h-1,ColorL //Links
DRAWLINE 0,h-1,w-1,h-1,ColorD //Unten
DRAWLINE w-1,0,w-1,h-1,ColorD //Rechts
ENDIF

LOCAL tx=0
LOCAL ty=0
IF self.typ=G_Window OR self.typ=G_Frame OR self.typ=G_Label OR self.typ=G_Checkbox OR self.typ=G_Option OR self.typ=G_Button  OR self.typ=G_Textbox
tx=w/2-TextWidth(self.text$)/2 //Mitte
ENDIF
IF self.typ=G_Window OR self.typ=G_Frame
//die nicht
ELSE
ty=h/2-TextHeight()/2
ENDIF


IF self.typ=G_Slider
//dient nur zum rumgeklicke
//Kugel Malen
//x  = -1 bis 1
//y  = -1 bis 1
//valuefx#
//valuefy#
PRINT "+",w/2-TextWidth("+")/2,h/2-TextHeight()/2
ELSEIF self.typ=G_List
//Liste hat kein Text , nur Inhalt
ELSE
PRINT self.text$,tx,ty //BitmapFont
ENDIF

IF self.typ=G_Checkbox AND self.valuei<>0 THEN PRINT " +",0,ty //BitmapFont
IF self.typ=G_Option AND self.valuei<>0 THEN PRINT " +",0,ty //BitmapFont
IF self.typ=G_Textbox AND self.valuei<>0 THEN PRINT " +",0,ty //BitmapFont

ENDIF //Sichtbar

ENDFUNCTION //Draw

FUNCTION Update: mx,my,b1,b2,bm,wheel,keyasc$

//...
//Wenn sichtbar und enabled und Focus bei Textbox den Text verändern

ENDFUNCTION //Uodate

FUNCTION CreateWindow AS TGui: x1,y1,x2,y2,text$

LOCAL G AS TGui
G.Init(G_Window,x1,y1,x2,y2,text$)
RETURN G

ENDFUNCTION

FUNCTION CreateLabel AS TGui: x1,y1,x2,y2,text$

LOCAL G AS TGui
G.Init(G_Label,x1,y1,x2,y2,text$)
RETURN G

ENDFUNCTION

FUNCTION CreateTextbox AS TGui: x1,y1,x2,y2,text$

LOCAL G AS TGui
G.Init(G_Textbox,x1,y1,x2,y2,text$)
RETURN G

ENDFUNCTION

FUNCTION CreateButton AS TGui: x1,y1,x2,y2,text$

LOCAL G AS TGui
G.Init(G_Button,x1,y1,x2,y2,text$)
RETURN G

ENDFUNCTION

FUNCTION CreateSlider AS TGui: x1,y1,x2,y2,text$

LOCAL G AS TGui
G.Init(G_Slider,x1,y1,x2,y2,text$)
RETURN G

ENDFUNCTION

FUNCTION CreateList AS TGui: x1,y1,x2,y2,text$

LOCAL G AS TGui
G.Init(G_List,x1,y1,x2,y2,text$)
RETURN G

ENDFUNCTION

FUNCTION CreateCheckbox AS TGui: x1,y1,x2,y2,text$

LOCAL G AS TGui
G.Init(G_Checkbox,x1,y1,x2,y2,text$)
RETURN G

ENDFUNCTION

FUNCTION CreateOption AS TGui: x1,y1,x2,y2,text$

LOCAL G AS TGui
G.Init(G_Option,x1,y1,x2,y2,text$)
RETURN G

ENDFUNCTION

FUNCTION CreateFrame AS TGui: x1,y1,x2,y2,text$

LOCAL G AS TGui
G.Init(G_Frame,x1,y1,x2,y2,text$)
RETURN G

ENDFUNCTION

ENDTYPE //Gui

FUNCTION G_ProcentToReal: px#,py#,BYREF x,BYREF y

LOCAL vx,vy,width,height
GETVIEWPORT vx,vy,width,height

px=px/100.0
py=py/100.0

    LOCAL m = MIN(width,height)

x=px*width  //m
y=py*height //m

    //DEBUG "px " + px + " py " +py +" x " + x + " y " +y  +"\n"

ENDFUNCTION

FUNCTION G_CreateBG:

LOCAL vx,vy,width,height
GETVIEWPORT vx,vy,width,height //merken Element drüber

LOCAL width=32,h=32

CREATESCREEN 0, bgsprite1, width, h

USESCREEN 0

LOCAL ly#,mu#,r,g,b
FOR ly=0 TO h-1
mu#=ly / (h-1)
r=Intp( 64.0 , 255.0 ,mu)
g=Intp( 64.0 , 255.0 ,mu)
b=Intp(128.0 ,255.0 ,mu)
DRAWLINE 0,ly,width-1,ly,RGB(r,g,b)
NEXT

CREATESCREEN 0, bgsprite2, width, h

USESCREEN 0

FOR ly=0 TO h-1
mu#=ly / (h-1)
r=Intp(255.0 , 64.0 ,mu)
g=Intp(255.0 , 64.0 ,mu)
b=Intp(255.0 ,128.0 ,mu)
DRAWLINE 0,ly,width-1,ly,RGB(r,g,b)
NEXT

CREATESCREEN 0, bgsprite3, width, h

USESCREEN 0

LOCAL ly#,mu#,r,g,b
FOR ly=0 TO h-1
mu#=ly / (h-1)
r=Intp( 0.0 , 128.0 ,mu)
g=Intp( 0.0 , 128.0 ,mu)
b=Intp( 0.0 , 128.0 ,mu)
DRAWLINE 0,ly,width-1,ly,RGB(r,g,b)
NEXT

USESCREEN -1

ENDFUNCTION

//Interpolation A to B
FUNCTION Intp#: a#,b#,mu# //mu = 0.0 bis 1.0
RETURN a+(b-a)*mu
ENDFUNCTION