Layout Programm im CanvasGadget

Du brauchst Grafiken, gute Programme oder Leute die dir helfen? Frag hier.
Phil
Beiträge: 32
Registriert: 05.07.2006 10:46

Layout Programm im CanvasGadget

Beitrag von Phil »

Hallo zusammen,

ich habe mich in den letzten Tagen mal wieder an PB gewagt und die Anfänge eines Layout Programms...
Da ich mich immer noch als Anfänger einstufe, würde ich euch bitten, den Code mal zu überfliegen, ob ihr daran grundsätzlich etwas ändern würdet.
Das nachträgliche Umstrukturieren bleibt zwar nie aus, aber vielleicht kann ich es so etwas eindämmen. ;-)
- Lieber Bindevent oder EventLoop?
- Ist Vectordrawing verlässlich in der Darstellung auch im Druck?
Nebenbei: Mir ist aufgefallen, dass beim Drucken von Text mit Alpha bei manchen Textgrößen eine sehr grobe Rasterung entsteht. Habt ihr eine Erklärung?

Bisher kann das Programm noch nicht viel:
- Grafik laden und in Form von ein paar Objekten darstellen
- Auswahl einzelner Objekte mit Möglichkeit zum Verschieben
- Zoomen mit Strg+Mausrad

Viele Grüße,
Phil

Code: Alles auswählen

; ------------------------------------------------------------
;
;   Layout Software - Canvas Vector Test
;
;    (c) Phil
;
; ------------------------------------------------------------
;



EnableExplicit

;- Constants

#testImage = 7
#Handle_Radius=3.0


Enumeration Mode
  #Mode_None
  #Mode_Move
EndEnumeration


;- Gadgets
#G_Canvas=5


;- Structures

Structure Object
  name.s
  image.i
  text.s
  x.f
  y.f
  w.f
  h.f
  flag_selected.b
EndStructure

;- Global 

Global Event.i
Global EventGadget.i
Global EventType.i

Global gMouseX.f
Global gMouseY.f
Global gRelativeSelObjMouseX.f
Global gRelativeSelObjMouseY.f

Global gScaleKoords.f = 1.0

Global gMode.i

Global NewList objList.Object()
Global NewList mouseOverList.i()
Global gUpMouseOverObj.i 
Global gSelectedObject.i = 3
Global gFlgMouseOverHandle.i
Global gFlgMouseOverSelObj.i
 
;- Procedures

Procedure CreateObject()
  
  AddElement(objList())
  
  With objList()
    \name = "test"
    \image = #testImage
    \x = Random(100,10)
    \y = Random(100,10)
    \w = Random(100,10)
    \h = Random(100,10)
  EndWith
  
EndProcedure

Procedure RedrawObjects()
  
  Protected x.f, y.f
  
  x = gMouseX
  y = gMouseY
  
  ;Make list of all Objects with MouseOver by silently drawing the frames.
  ForEach objList()
    With objList()
          
      AddPathBox(\x, \y,\w ,\h)
      If IsInsidePath(x, y, #PB_Coordinate_User)
        VectorSourceColor(RGBA(255, 255, 0, 255))
        AddElement(mouseOverList())
        mouseOverList()=ListIndex(objList())
      Else
        VectorSourceColor(RGBA(0, 255, 0, 255))
      EndIf
      
      ResetPath()
      ;       StrokePath(0.4)       
    EndWith
  Next
  
  ;select upmost object and draw all objects.
  If LastElement(mouseOverList())
    Protected upObj.i= mouseOverList()+1
    ResetList(mouseOverList())
  Else
    upObj=0
    gUpMouseOverObj=0
  EndIf
  
  Protected curObjNr.i
  
  ForEach objList()
    curObjNr = ListIndex(objList())+1
    
    With objList()
      
      ;If Mode_Move, set new position of selObj
      If curObjNr=gSelectedObject 
        Select gMode            
          Case #Mode_Move
            \x=x-gRelativeSelObjMouseX
            \y=y-gRelativeSelObjMouseY
            ;Make it eventually snap to a grid??
            \x=Round(\x,#PB_Round_Nearest)
            \y=Round(\y,#PB_Round_Nearest)
            
        EndSelect
      EndIf
      
      ;Draw Image and PathBox
      MovePathCursor(\x,\y)
      DrawVectorImage(ImageID(\image),255,\w,\h)
      
      AddPathBox(\x, \y,\w ,\h)
      
      ;Check selObj for MouseOver
      If curObjNr=gSelectedObject 
        If IsInsidePath(x, y, #PB_Coordinate_User)
          gFlgMouseOverSelObj=#True
        Else
          gFlgMouseOverSelObj=#False
        EndIf
      EndIf
      
      If IsInsidePath(x, y, #PB_Coordinate_User)
        
        If curObjNr=upObj ; Wenn das Object das oberste ist, durchgeben und färben
          gUpMouseOverObj=upObj
          VectorSourceColor(RGBA(255, 50, 0, 255))
        Else
          VectorSourceColor(RGBA(255, 255, 0, 255))
        EndIf
      Else
        VectorSourceColor(RGBA(0, 255, 0, 255))
      EndIf
      
      StrokePath(ConvertCoordinateX(0.4,0,#PB_Coordinate_Output,#PB_Coordinate_User))     
    EndWith
  Next
  
  ClearList(mouseOverList())
  
EndProcedure

Procedure RedrawSelection()
  
  Protected hR.f
  Protected x.f, y.f
  
  x = gMouseX
  y = gMouseY

  hR = ConvertCoordinateX(#Handle_Radius,0,#PB_Coordinate_Output,#PB_Coordinate_User)
  
  gFlgMouseOverHandle.i=#False
  
  If gSelectedObject
    
    SelectElement(objList(),gSelectedObject-1)
    
    With objList()
      
      
      ;Draw Box around Object.
      AddPathBox(\x,\y,\w,\h)
      VectorSourceColor(RGBA(50,50,255,100))
      DashPath(ConvertCoordinateX(0.6,0,#PB_Coordinate_Output,#PB_Coordinate_User),2.0)
      
      
      ;Draw HandleCircles round selectedObject and check for MouseOver.
      AddPathCircle(\x,\y,hR)
      If Not gFlgMouseOverHandle And IsInsidePath(x, y, #PB_Coordinate_User) : gFlgMouseOverHandle=1 : EndIf     
      AddPathCircle(\x+\w,\y,hR)
      If Not gFlgMouseOverHandle And IsInsidePath(x, y, #PB_Coordinate_User) : gFlgMouseOverHandle=2 : EndIf
      AddPathCircle(\x,\y+\h,hR)
      If Not gFlgMouseOverHandle And IsInsidePath(x, y, #PB_Coordinate_User) : gFlgMouseOverHandle=3 : EndIf
      AddPathCircle(\x+\w,\y+\h,hR)
      If Not gFlgMouseOverHandle And IsInsidePath(x, y, #PB_Coordinate_User) : gFlgMouseOverHandle=4 : EndIf
      AddPathCircle(\x+\w/2,\y+\h/2,hR)
      If Not gFlgMouseOverHandle And IsInsidePath(x, y, #PB_Coordinate_User) : gFlgMouseOverHandle=5 : EndIf
      VectorSourceColor(RGBA(50,50,255,150))
      FillPath()
      
      
    EndWith
  EndIf
  
EndProcedure


Procedure RedrawAll(x.f,y.f)
  
  If StartVectorDrawing(CanvasVectorOutput(#G_Canvas,#PB_Unit_Millimeter))
    
    Protected i.i, imgWidth.f, imgHeight.f
    
    ScaleCoordinates(gScaleKoords,gScaleKoords)
    
    
;     imgWidth = ConvertCoordinateX(ImageWidth(#testImage),0,#PB_Coordinate_Device,#PB_Coordinate_Output)
;     imgHeight =  ConvertCoordinateY(0,ImageHeight(#testImage),#PB_Coordinate_Device,#PB_Coordinate_Output)
    
;     gMouseX = ConvertCoordinateX(x,y,#PB_Coordinate_Device,#PB_Coordinate_Output)
;     gMouseY = ConvertCoordinateY(x,y,#PB_Coordinate_Device,#PB_Coordinate_Output)
    gMouseX = ConvertCoordinateX(x,y,#PB_Coordinate_Device,#PB_Coordinate_User)
    gMouseY = ConvertCoordinateY(x,y,#PB_Coordinate_Device,#PB_Coordinate_User)
    
    ;Clear whole Canvas and draw sheet of Paper.
    VectorSourceColor(RGBA(100,100,100, 255))
    FillVectorOutput()
    VectorSourceColor(RGBA(50,50,50, 255))
    AddPathBox(10.5,10.5,145,210)
    FillPath()
    VectorSourceColor(RGBA(240,240,240, 255))
    AddPathBox(10,10,145,210)
    FillPath()
    
    
    
    
    ;Draw objects and check for mouseover.
    RedrawObjects()
    
    RedrawSelection()
    
    
;     ;Testdraw für Coordinaten.
;     AddPathBox(gMouseX, gMouseY, 10,20)
;     VectorSourceColor(RGBA(Random(255), Random(255), Random(255), 255))
;     FillPath()

    
    StopVectorDrawing()
  EndIf
  
EndProcedure

Procedure SetRelMousePos()
  
  Protected selObj.i
  
  SelectElement(objList(),gSelectedObject-1)
  gRelativeSelObjMouseX = gMouseX- objList()\x
  gRelativeSelObjMouseY = gMouseY- objList()\y
  
;   Debug gRelativeSelObjMouseX
EndProcedure


If OpenWindow(0, 0, 0, 900, 900, "VectorDrawing", #PB_Window_SystemMenu | #PB_Window_ScreenCentered|#PB_Window_MaximizeGadget)
  CanvasGadget(#G_Canvas, 0, 0, 900, 900)
  UsePNGImageDecoder()
  Define file.s
  file = OpenFileRequester("Wähle Bilddatei (.png) aus.",GetCurrentDirectory(),"png-Image|*.png",0)
  If Not LoadImage(#testImage, file):MessageRequester("Fehler", "Ohne Bild kein Programm! ;-)"):End:EndIf
  ResizeImage(#testImage,250,400)
  
  gMode = #Mode_None
  
  Define i.i
  For i=0 To 8
    CreateObject()
  Next
  
  ;Initial drawing
  RedrawAll(0,0)
   
  
  
  ;- Event-Loop
   
  Repeat
    Event = WaitWindowEvent()
    
    If Event=#PB_Event_Gadget
      Global Gadget = EventGadget()
      Global EventType = EventType()
      
      Select Gadget
        Case #G_Canvas ;Canvas Gadget Event
          
          Select EventType
              
            Case #PB_EventType_MouseMove
              ;Refresh Canvas on every move. and check for MouseOver!
              RedrawAll(GetGadgetAttribute(#G_Canvas,#PB_Canvas_MouseX),GetGadgetAttribute(#G_Canvas,#PB_Canvas_MouseY))
              
              ;If Handle MouseOver, show hand symbol.
              If gFlgMouseOverHandle
                SetGadgetAttribute(#G_Canvas,#PB_Canvas_Cursor,#PB_Cursor_Hand)
              Else
                SetGadgetAttribute(#G_Canvas,#PB_Canvas_Cursor,#PB_Cursor_Default)
              EndIf
              
              
              
            Case #PB_EventType_LeftButtonDown 
              
              ;Only change selected Object if LeftClick was not on selObj or Handle!
              If Not (gFlgMouseOverHandle Or gFlgMouseOverSelObj)
                gSelectedObject=gUpMouseOverObj 
              EndIf
              
              ;If clicked on selObj, start move and register rel pos of Cursor.
              If gFlgMouseOverSelObj
                gMode = #Mode_Move
                SetRelMousePos()
              EndIf
              
              
              If GetGadgetAttribute(#G_Canvas,#PB_Canvas_Buttons)=#PB_MouseButton_Left
                
              EndIf

            Case #PB_EventType_LeftButtonUp              
              gMode = #Mode_None
              
              
            Case #PB_EventType_MouseWheel
              Define delta.i
              delta =GetGadgetAttribute(#G_Canvas,#PB_Canvas_WheelDelta)
              
              If GetGadgetAttribute(#G_Canvas,#PB_Canvas_Modifiers) = #PB_Canvas_Control
                gScaleKoords*(1.0+delta*0.1)
                If gScaleKoords<0.4: gScaleKoords=0.4:EndIf
                If gScaleKoords>3.0: gScaleKoords=3.0:EndIf
                RedrawAll(GetGadgetAttribute(#G_Canvas,#PB_Canvas_MouseX),GetGadgetAttribute(#G_Canvas,#PB_Canvas_MouseY))
              EndIf
              
          EndSelect
            
        EndSelect
      EndIf
      
      
    Until Event = #PB_Event_CloseWindow
  EndIf
  
PB 5.62 on Win10
Benutzeravatar
TheCube
Beiträge: 150
Registriert: 20.07.2010 23:59
Computerausstattung: Risen 3400G 16MB Win10-64Bit
Wohnort: NRW

Re: Layout Programm im CanvasGadget

Beitrag von TheCube »

Habe deinen Code nur mal ausprobiert ... zu deinen Fragen mögen kompetentere Leute hier was sagen.
Was mir aber auffiel:
- Das Zoomen mit Strg+Mausrad geht bei mir nicht (oder ich bediene es falsch ?)
- Jegliche andauernde Mausbewegung im Fenster, ob neben oder auf Grafikobjekt, lastet einen Kern 100% aus.

Aber das Einrahmen der Grafikobjekte mit den Anpackpunkten usw. sieht aber gut aus.
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: Layout Programm im CanvasGadget

Beitrag von ccode_new »

@Phil

Sieht toll aus.

Beide von "TheCube" genannten Punkte kann ich weder unter Linux, noch unter Windows bestätigen.

Das Zoomen funktioniert bei mir unter Linux und Windows und lastet bei mir keinen Kern voll aus.
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Lord
Beiträge: 313
Registriert: 21.01.2008 19:11

Re: Layout Programm im CanvasGadget

Beitrag von Lord »

Hallo!
TheCube hat geschrieben:...
Was mir aber auffiel:
- Das Zoomen mit Strg+Mausrad geht bei mir nicht (oder ich bediene es falsch ?)
...
Da kann ich bestätigen.
Abhilfe schafft das Flag #PB_Canvas_Keyboard beim öffnen des Canvas.
TheCube hat geschrieben:...
Was mir aber auffiel:
...
- Jegliche andauernde Mausbewegung im Fenster, ob neben oder auf Grafikobjekt, lastet einen Kern 100% aus.
...
Dieses Verhalten kann ich nicht betätigen.
Phil hat geschrieben:...
Lieber Bindevent oder EventLoop?
...
Das ist wohl Geschmackssache. Ich bevorzuge inzwischen BindEvent/BindGadgetEvent.
Bild
Benutzeravatar
dige
Beiträge: 1182
Registriert: 08.09.2004 08:53

Re: Layout Programm im CanvasGadget

Beitrag von dige »

@Phil: das ist schon ein toller Anfang - weiter so! :allright:
"Papa, mein Wecker funktioniert nicht! Der weckert immer zu früh."
Benutzeravatar
TheCube
Beiträge: 150
Registriert: 20.07.2010 23:59
Computerausstattung: Risen 3400G 16MB Win10-64Bit
Wohnort: NRW

Re: Layout Programm im CanvasGadget

Beitrag von TheCube »

Habe das mit der Kern-Vollauslastung sicherheitshalber nochmal geprüft.
Die zwei Rechner waren Idle, der Code aus PB gestartet (ohne Debugger), unbewegte Maus, die CPU Auslastung meist 0%.

Dann lasse ich den Mauszeiger im Codefenster kreisen, nur im freien Bereich oder nur im Grafikobjekt,
damit die Grafikobjektrahmen nicht immer updaten:
Atom 2-Kerner mit HT : 4 Threads : Gesamt 25% Auslastung durchgehend
Core i5-4430S 4-Kerner : 4 Threads : Gesamt 25% Auslastung durchgehend

Stoppe ich das "Kreisen" (Auch mit Mauszeiger weiterhin im Codefenster) fällt die Auslastung sofort wieder auf 0%.
Benutzeravatar
#NULL
Beiträge: 2235
Registriert: 20.04.2006 09:50

Re: Layout Programm im CanvasGadget

Beitrag von #NULL »

Geht hier unter linux.
Ich habe bei durchgängigem mousemove auch einen Kern ausgelastet. Ist aber denke ich normal, wenn bei jedem mousemove immer alles neu gezeichnet wird, inklusive der mehrfachen DrawVectorImage()s.
my pb stuff..
Bild..jedenfalls war das mal so.
Phil
Beiträge: 32
Registriert: 05.07.2006 10:46

Re: Layout Programm im CanvasGadget

Beitrag von Phil »

Wow! Vielen Dank für die positiven Rückmeldungen! :allright:

Eine Frage hätte ich zum Forum. Wenn ich den Code aktualisiere, mache ich das dann als Edit im ersten Post oder besser in einer neuen Antwort?

Zum Programm:
- Am Neuzeichnen bei Mousemove komme ich wohl nicht herum, wenn ich die Objekte zum Selektieren farblich hervorheben will. Ideen für weniger Auslastung?
- Beim Verschieben eines Objektes könnte ich eventuell einen Snapshot der oberen und unteren Objekte darstellen statt alles neu zu zeichnen, bei einer Auswahl mehrerer Objekte wird das aber schnell kompliziert....

Phil
Zuletzt geändert von Phil am 26.10.2018 16:43, insgesamt 1-mal geändert.
PB 5.62 on Win10
Benutzeravatar
TroaX
Beiträge: 659
Registriert: 08.03.2013 14:27
Computerausstattung: PC: Ryzen 9 3950X, 96 GB RAM, RX6800XT, 2.5 TB SSD, 21:9 Display, Pop_OS! | Lappi: Ryzen 7 5800H, 16 GB RAM, 1 TB SSD, Pop_OS!
Wohnort: NRW
Kontaktdaten:

Re: Layout Programm im CanvasGadget

Beitrag von TroaX »

Du selektierst ja wahrscheinlich auch in Verbindung mit einer weiteren Taste. Bei jedem Mousemove ist definitiv neu zeichnen viel zu viel. Ich würde neben der Bewegung prüfen, ob eine Taste gedrückt wird und dann erst neu zeichnen. Außerdem versuch es mal mit einem sehr kurzem Delay von 1 - 5 ms. Das bewirkt schon Wunder.
PC: Ryzen 9 3950X | 96 GB RAM | RX6800XT | 2,5 TB NVMe | Pop_OS!
Notebook: 16" 3:2 | Ryzen 7 5800H | 16 GB RAM | Radeon Vega | 1TB NVMe | Pop_OS!
NAS: Fritz.Box :lol:
Coding: Purebasic 6.04 | PHP | HTML | CSS | Javascript
Phil
Beiträge: 32
Registriert: 05.07.2006 10:46

Re: Layout Programm im CanvasGadget

Beitrag von Phil »

Du selektierst ja wahrscheinlich auch in Verbindung mit einer weiteren Taste.
Selektieren ja, mit LinksKlick, aber es geht um die Aktualisierung der farblichen Markierung, welches Objekt bei Klick ausgewählt wird.

Was meinst du mit Delay? Hab es mit 5 ms Timeout in WaitWindowEvent und Delay(5) in der EventLoop versucht.
Bringt bei mir eine Verbesserung von 15% auf 11%. Bei Delay(10) auf 8% gesamt.
PB 5.62 on Win10
Antworten