Tortenmenü, yumi!

Für allgemeine Fragen zur Programmierung mit PureBasic.
Lambda
Beiträge: 526
Registriert: 16.06.2011 14:38

Tortenmenü, yumi!

Beitrag von Lambda »

Ich benötige die Ausrichtung verschieden breiter Menü-Elemente um einen Punkt herum. Es können beliebig viele und beliebig breite sein, daher sollte es keine Überlappungen geben. Zeitlich bin ich gerade etwas ausgelastet daher würde ich mich freuen wenn jemand eine schicke Lösung formen könnte.

Sandkasten-Code:

Code: Alles auswählen

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

Procedure.f lendirx(Length.f, Direction.f)
  ProcedureReturn Cos(Direction*#PI/180)*Length
EndProcedure

Procedure.f lendiry(Length.f, Direction.f)
  ProcedureReturn -Sin(Direction*#PI/180)*Length
EndProcedure


Structure ITEM
  x.f
  y.f
  a.f
  c.i
  Size.SIZE
EndStructure

Global NewList Item.ITEM(), i

For i=0 To 10
  AddElement(Item())
  Item()\Size\cx = 80
  Item()\Size\cy = 20
  Item()\c = RGB(Random(255),Random(255),Random(255))
Next

StartDrawing(CanvasOutput(0))
  ForEach Item()
    Item()\a = (360/ListSize(Item()))*ListIndex(Item())
  Next
  
  Define *Pre.ITEM
ForEach Item()
  
  Item()\x = lendirx(120, Item()\a)
  Item()\y = lendiry(60, Item()\a)
  
  
  *Pre = @Item()
Next

ForEach Item()
  Box(200+Item()\x, 150+Item()\y, 80, 20, Item()\c)
Next

ForEach Item()
  DrawText(200+Item()\x, 150+Item()\y,Str(Item()\a))
Next
StopDrawing()


Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      End
  EndSelect
ForEver
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7039
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Tortenmenü, yumi!

Beitrag von STARGÅTE »

Wenn es keine Überlappung geben darf, und auf jedenfall N Elemente verteilt werden sollen, musst du aber zwangsweise einen Fit-Parameter zur Verfügung stellen, welcher?
  • Soll der Radius vergrößert werden?
    Nur synchron? oder zwei unabhängige Radien?
  • Soll die Schrift verkleinert werden?
    Alle zusammen oder unterschiedliche Schriftgrößen?
  • Darf die Reihenfolge der Menüpunkte vertauscht werden?
    Breite Elemente eignen sich ja besser links und rechts, statt oben und unten.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Lambda
Beiträge: 526
Registriert: 16.06.2011 14:38

Re: Tortenmenü, yumi!

Beitrag von Lambda »

Der Radius kann natürlich verändert werden, auch etwas oval. :) Die Reihenfolge wäre wichtig, da die Elemente dann in allen Sprachen die selbe Reihenfolge einhalten sollten.
Lambda
Beiträge: 526
Registriert: 16.06.2011 14:38

Re: Tortenmenü, yumi!

Beitrag von Lambda »

Findet sich noch jemand?
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: Tortenmenü, yumi!

Beitrag von Danilo »

Für was brauchst Du das denn genau? Vielleicht ist ein Carousel control geeigneter für ein Menu?
"Es können beliebig viele sein", also auch Tausende, ist schon etwas sehr allgemein gehalten. Dann würde das Tortenbild riesig werden.
Für ein (übersichtliches) Menu sollten doch maximal 20-25 Einträge meist ausreichen?
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Lambda
Beiträge: 526
Registriert: 16.06.2011 14:38

Re: Tortenmenü, yumi!

Beitrag von Lambda »

"Beliebig viele" war eher darauf bezogen, dass die Anzahl ständig variiert und mal eine gerade als auch ungerade Anzahl (bestenfalls symmetrisch) verteilt werden muss. Ja, mehr als 20 pro Menü sind es nicht :).

Wären es simple Symbole mit fester Größe wäre das kein Ding, genaueres Beispiel wäre das Menü aus "Die Sims", genau ein solches benötige ich. :)
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7039
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Tortenmenü, yumi!

Beitrag von STARGÅTE »

Aber in dem Bild ist ja eindeutig zu sehen, dass die beiden klein Einträge obne und unten angelegt wurden und die großen an die Seite. Also eine sortierung!
Das möchtest du ja nicht haben.

Man müsste also in deinem Modell zunächst mal alle Einträge anlegen und dann alle Winkel von 0-360° durchlaufen und den Winkel mit der geringsten Überschneidung finden.
Danach vergrößert man den Radius, biss die Überschneidung weg ist.

Mein erster Lösungsweg wäre also iterativ, weiß aber nicht ob dir das reicht?
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: Tortenmenü, yumi!

Beitrag von Danilo »

Code: Alles auswählen

Structure ITEMRECT
    x.i
    y.i
    width.i
    height.i
EndStructure

Structure ITEM
  text.s
  textColor.i
  rect.ITEMRECT
EndStructure

Procedure DrawItems(x,y,List items.ITEM(),linespacing=0)
    itemCount = ListSize( items() )
    If itemCount = 0
        ProcedureReturn
    EndIf
    
    ForEach items()
        items()\rect\width  = TextWidth(  items()\text )+4
        items()\rect\height = TextHeight( items()\text )+4+linespacing
    Next
    
    FirstElement( items() )
    
    If itemCount = 1
        items()\rect\x = x - items()\rect\width  * 0.5
        items()\rect\y = y - items()\rect\height * 0.5
    ElseIf itemCount = 2
        items()\rect\x = x - items()\rect\width  * 0.5
        items()\rect\y = y - items()\rect\height - 1
        NextElement( items() )
        items()\rect\x = x - items()\rect\width  * 0.5
        items()\rect\y = y + 1
    Else
        mod = ((itemCount - 2) % 2)
        left = (itemCount - 2) / 2 + mod
        right = itemCount - 2 - left
        height = left * (items()\rect\height)
        
        items()\rect\x = x - items()\rect\width * 0.5
        items()\rect\y = y - items()\rect\height - 4 - (height * 0.5)
        isLeft = 1 : new_y = y - height * 0.5
        line = 1
        items = left
        winkel.f = 180/(items+1)
        For i = 1 To itemCount - 2
            NextElement( items() )
            If isLeft
                x_off = Cos(Radian(-90+(line)*winkel)) * height * 0.5
                items()\rect\x = x - items()\rect\width - 1 - x_off
                items()\rect\y = new_y
                isLeft ! 1
            Else
                items()\rect\x = x + 1 + x_off ;+ items()\rect\height * 0.5
                items()\rect\y = new_y
                isLeft ! 1
                new_y + items()\rect\height + 2
                line + 1
            EndIf

        Next
        If NextElement( items() )
            If left = right
                ;new_y + items()\rect\height + 2
                items()\rect\x = x - items()\rect\width  * 0.5
                items()\rect\y = new_y
            Else
                items()\rect\x = x + 1 + x_off ;+ items()\rect\height * 0.5
                items()\rect\y = new_y
            EndIf
        EndIf
    EndIf
    
    ForEach items()
        DrawingMode(#PB_2DDrawing_Gradient)
        ResetGradientColors()
        BackColor(RGB(0,0,255))
        FrontColor(RGB(255,0,0))
        LinearGradient(items()\rect\x, items()\rect\y, items()\rect\x+items()\rect\width, items()\rect\y+items()\rect\height)
        Box(items()\rect\x, items()\rect\y, items()\rect\width, items()\rect\height-linespacing)
        
        DrawingMode(#PB_2DDrawing_Transparent)
        DrawText( items()\rect\x+2, items()\rect\y+2, items()\text, items()\textColor)
    Next
EndProcedure

Procedure GenerateEntries(count,List items.ITEM())
    ClearList( items() )
    If count
        For i=1 To count
            AddElement(Items())
            Items()\text = "Menu "+Str(i)+" "
            For j = 0 To Random(50)
                items()\text + Chr(Random(25)+'a')
            Next
            Items()\textColor = RGB(255,255,255)
        Next
    EndIf
EndProcedure

NewList Items.ITEM()



OpenWindow(0, 0, 0, 800, 600, "", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)
CanvasGadget(0, 0, 0, WindowWidth(0)-100, WindowHeight(0))
SpinGadget(1,WindowWidth(0)-90,10,80,20,1,50)
SetGadgetState(1,8)
SetGadgetText(1,Str(GetGadgetState(1)))



LoadFont(1,"Arial",20)

GenerateEntries(GetGadgetState(1),Items())

If StartDrawing( CanvasOutput(0) )
    DrawingFont(FontID(1))
    DrawItems( OutputWidth()*0.5, OutputHeight()*0.5, Items(), 2 )
    StopDrawing()
EndIf

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
        End
    Case #PB_Event_Gadget
        If EventGadget()=1
            count = GetGadgetState(1)
            SetGadgetText(1,Str(count))
            GenerateEntries(count,Items())
            If StartDrawing( CanvasOutput(0) )
                Box(0,0,OutputWidth(),OutputHeight(),RGB(255,255,255))
                DrawingFont(FontID(1))
                DrawItems( OutputWidth()*0.5, OutputHeight()*0.5, Items(), 5 )
                StopDrawing()
            EndIf
        EndIf
  EndSelect
ForEver
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Lambda
Beiträge: 526
Registriert: 16.06.2011 14:38

Re: Tortenmenü, yumi!

Beitrag von Lambda »

Exzellent Danilo! :D Danke dir, sogar mit aufgehübschten Beispiel. ^^
Antworten