Results 1 to 34 of 34

Thread: Graphics question: A challenge to guru!

  1. #1

    Thread Starter
    Member
    Join Date
    Sep 2003
    Posts
    47

    Graphics question: A challenge to guru!

    Hi all!

    2 years ago, I've asked around and even searched on the net on how to indicate if a given point(in coordinates) belongs inside an ellipse. I've got that code if you guys want (in C++).

    However, today I have one simple question, I hope it's simple enough if anyone knows, I am too busy to try out to make a formula for it. Now the question.

    You draw a line using the DrawLine function which requires 2 points and of course a pen object.
    Take for example i have 2 points, 1 point at coordinate (2,10) and the other point at (30, 47).

    The question is how do you determine if a given point let say maybe 7,7 belongs to the line plotted/drawn by the DrawLine
    function?

    Archaven

  2. #2
    Frenzied Member
    Join Date
    Oct 2002
    Location
    Gammapolis
    Posts
    1,474
    Well, for the line you can simply make the line formula and test the point with it in the range of two points. That's the matter of two lines of code, but even for the line or for more complicated shapes it can be done using GraphicsPath and IsVisible method. Want some code?
    Last edited by Lunatic3; Nov 29th, 2003 at 03:39 AM.
    'Heading for the automatic overload'
    Marillion, Brave, The Great Escape, 1994

    'How will WE stand the FIRE TOMORROW?'
    Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979

  3. #3

    Thread Starter
    Member
    Join Date
    Sep 2003
    Posts
    47

    Flicker free drawing?

    Hi thanks for the reply!. It helps alot!. In the meantime, i have one more question. I am using the panel control as the drawing canvas. I have few objects painted in the panel. Around 20-30 objects which includes lines, ellipses, rectangles, texts, etc. Although there aren't many objects drawn in the panel, each time when a process is done and i need to redraw/refresh all objects, I used the Invalidate/Refresh/Update functions. All of these functions causes flickering. I've tried using the SmoothingMode = SmoothingMode.HighSpeed but it's still flickers horribly. Any suggestion ?

    Thanks in advance.
    Archaven

  4. #4
    Frenzied Member
    Join Date
    Oct 2002
    Location
    Gammapolis
    Posts
    1,474
    This is for checking if the point is inside a line, but with some modification you can use it for any other shape too.
    VB Code:
    1. Private Function IsInside(ByVal xa As Point, ByVal xb As Point, ByVal xc As Point) As Boolean
    2.         Dim gp As New Drawing.Drawing2D.GraphicsPath
    3.         gp.AddLine(xa, xb)
    4.         ' IsVisble method does not check for the points on borders,
    5.         ' so we have to widen the region by one pixel to include the points on the border
    6.         gp.Widen(New Pen(Color.Black, 1))
    7.         IsInside = gp.IsVisible(xc)
    8.         gp.Dispose()
    9. End Function
    For you other question, to reduce flicker you may use double buffering. So:
    VB Code:
    1. SetStyle(ControlStyles.UserPaint, True)
    2. SetStyle(ControlStyles.AllPaintingInWmPaint, True)
    3. SetStyle(ControlStyles.DoubleBuffer, True)
    Also my experience with drawing is GraphicsPath offer a higher performance than directly drawing. You add all the objects to the path and then draw the path.
    'Heading for the automatic overload'
    Marillion, Brave, The Great Escape, 1994

    'How will WE stand the FIRE TOMORROW?'
    Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979

  5. #5

    Thread Starter
    Member
    Join Date
    Sep 2003
    Posts
    47
    Hey Lunatic, thanks for the quick reply. There's one more question that i have on mind.

    If i have a few objects drawn using the graphicspath, for eg. 3 same objects (maybe ellipses). I can determine if a point is inside any of those objects by using the IsVisible function.

    But how do i determine which ellipse has the focus? For eg. if a point is inside the 2nd ellipse, i would like to redraw that ellipse using a different color pen to indicate that the 2nd ellipse is being selected.

    Thanks again.
    Archaven

  6. #6
    Frenzied Member
    Join Date
    Oct 2002
    Location
    Gammapolis
    Posts
    1,474
    I think for 2 reasons you can not do that with a single GraphicsPath (GP).
    1- GP is a collection of points not shapes.
    2- GP does not contain any data about the pen or brush object you going to paint with. So even if you can decide which ellipse the point belongs to, you can not just draw that part of the GP with another color.

    So my advice is to go with a collection of GPs. Then check in the list and see your point is inside what GP, then redraw that path.
    'Heading for the automatic overload'
    Marillion, Brave, The Great Escape, 1994

    'How will WE stand the FIRE TOMORROW?'
    Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979

  7. #7

    Thread Starter
    Member
    Join Date
    Sep 2003
    Posts
    47
    Hi Lunatic. Thanks for the reply.

    I have a canvas (a panel control) and i need to draw grids in it. Below is the code snippets that i've written:

    Code:
    Public Sub DrawGrid(ctlCanvas as Panel, szGrid as size)
        Dim col, row, cols, rows, x1, y1 As Integer
        Dim penGrid As New Pen(Color.DimGray)
    
        hGraphics = ctlCanvas.CreateGraphics
    
        cols = ctlCanvas.Width / szGrid.Width
        rows = ctlCanvas.Height / szGrid.Height
    
        x1 = szGrid.Width
        y1 = szGrid.Height
    
        For row = 0 To rows - 1
            For col = 0 To cols - 1
                hGraphics.DrawLine(penGrid, x1, y1, x1 + CSng(0.1), y1 + CSng(0.1))
                x1 += szGrid.Width
            Next
    
            y1 += szGrid.Height
            x1 = szGrid.Width
        Next
        hGraphics.SmoothingMode = SmoothingMode.HighSpeed
    
    End Sub
    I've noticed that the performance are horribly slow(of course without the double buffering yet) especially with a very large canvas size. Just wish to know if there's a better solution than this which could increase the performance.
    This function is a frequently called function. I will always need to execute it in the OnPaint event.

    Thanks again,
    Archaven
    Last edited by Archaven; Nov 30th, 2003 at 09:41 PM.

  8. #8
    Frenzied Member
    Join Date
    Oct 2002
    Location
    Gammapolis
    Posts
    1,474
    GDI+ is not that fast anyway. However try double buffring and also you can use ControlPaint.DrawGrid to draw a grid.
    'Heading for the automatic overload'
    Marillion, Brave, The Great Escape, 1994

    'How will WE stand the FIRE TOMORROW?'
    Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979

  9. #9
    Frenzied Member
    Join Date
    Oct 2002
    Location
    Gammapolis
    Posts
    1,474
    And by the way, I am sure that you can not draw a fraction of a pixel so you may not bother with CSng to draw a tiny dot. This is what I have come across so far:

    For example:
    DrawLine(1,1,1,1): Draws nothing
    DrawLine(1,1,2,1): Draws a 2 pixel long line
    DrawLine(1,1,1.5F,1): Draws 1 pixel (anything less than 0.5F and more than 0.0F. Ofcourse this is in theory. Infact it will not draw anything if you add something less than aproximately 0.002F)
    DrawLine(1,1,1.51F,1): Draws a 2 pixel long line (anything more than 0.5F and less or equal to 1F)

    So using your method, if you come to a x1 + CSng(0.1) and/or a y1 + CSng(0.1) that rounds up, you will have a line that is more than 1 pixel in lenght, vertically, horizontally or both.
    Last edited by Lunatic3; Dec 1st, 2003 at 01:29 AM.
    'Heading for the automatic overload'
    Marillion, Brave, The Great Escape, 1994

    'How will WE stand the FIRE TOMORROW?'
    Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979

  10. #10

    Thread Starter
    Member
    Join Date
    Sep 2003
    Posts
    47
    Hey Lunatic!. Thanks for the reply again.

    I've tried using the ControlPaint.Drawgrid function and it seems to me that it didn't draw anything to the screen?

    Code:
    Private Sub pnlCanvas_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles pnlCanvas.Paint
    
        pnlCanvas.SuspendLayout()
    
        Dim rectArea As New Rectangle(pnlCanvas.Left, pnlCanvas.Top, pnlCanvas.Width, pnlCanvas.Height)
    
        Dim hGraphics As Graphics = pnlCanvas.CreateGraphics
        ControlPaint.DrawGrid(hGraphics, rectArea, szGrid, Color.DimGray)
    
        pnlCanvas.ResumeLayout()
    
    End Sub
    I think i found where the error was. Color.DimGray (Duh!) How silly :P

    Btw, where do i call these codes?

    Code:
    SetStyle(ControlStyles.UserPaint, True)
    SetStyle(ControlStyles.AllPaintingInWmPaint, True)
    SetStyle(ControlStyles.DoubleBuffer, True)
    The SetStyle function is not a member of the panel class. If i call these functions on form load, does it applies to the form/panel control?

    Thanks
    Last edited by Archaven; Dec 1st, 2003 at 10:28 PM.

  11. #11
    Frenzied Member
    Join Date
    Oct 2002
    Location
    Gammapolis
    Posts
    1,474
    There are some problems with your code:
    1- Leave out those two lines SuspenedLayout and ResumeLayout, they won't do what you need. Look at this thread:
    http://www.vbforums.com/showthread.p...hreadid=264761
    2- The cordinations of the rectangle you want to draw in are relative to your control, so you should set the top and left proprties of it to 0 if you want to draw from the top of the canvas not to pnlCanvas.Left and pnlCanvas.Top as they reflect the position of canvas on its parent control.
    3- If you are painting in the paint event of control you can get use of e and not create another graphics, so this line
    Dim hGraphics As Graphics = pnlCanvas.CreateGraphics
    would better be:
    Dim hGraphics As Graphics = e.Graphics
    4-There is a size property in controls called ClientSize and that is the size of the control you can draw on, and is not necessarily equal to control width and height, as these contain borders, scrollbars,... but with a borderless panel i guess you can use any of them.
    5- The backColor parameter of drawgrid method is used to calculate the fill color of the dots so that the grid is always visible against the background.

    Yes, I think you can call the setstyle there or somewhere in the wizard generated code.
    Last edited by Lunatic3; Dec 1st, 2003 at 10:53 PM.
    'Heading for the automatic overload'
    Marillion, Brave, The Great Escape, 1994

    'How will WE stand the FIRE TOMORROW?'
    Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979

  12. #12
    Frenzied Member Magiaus's Avatar
    Join Date
    Mar 2002
    Location
    swamp land
    Posts
    1,267

    I have a sugestion

    For your grid make a very small memory image 3px x 3px make a cross inside it the use this image to fill your area. instan grid. And although I haven't tested it, it should be super fast.

    Double Buffering/Drawing in memory/Drawing off screen is the way to go. it reduces any flicking and mastering it allows you to layer your images like a photoshop documnet. The layers in the a PSD are individual dhc's stacked on a z-oreder. I haven't done more then lite work with GDI+ but it seems okay. I wouldn't use it to make a 3D game engine but it's okay....
    Magiaus

    If I helped give me some points.

  13. #13
    Sleep mode
    Join Date
    Aug 2002
    Location
    RUH
    Posts
    8,083
    I don't mean interruption but for the SetStyle method , it's ideal to put that in the constructor of your form (so you are requestiong double buffer prior to any drawing operation) , if this issue has to do with UC , then put that in the Set part of the property .

  14. #14
    Frenzied Member
    Join Date
    Oct 2002
    Location
    Gammapolis
    Posts
    1,474
    Originally posted by Pirate
    I don't mean interruption but for the SetStyle method , it's ideal to put that in the constructor of your form (so you are requestiong double buffer prior to any drawing operation) , if this issue has to do with UC , then put that in the Set part of the property .
    Actually I meant in form constructor by 'somewhere in the wizard generated code'. Thanks for clearing it.
    'Heading for the automatic overload'
    Marillion, Brave, The Great Escape, 1994

    'How will WE stand the FIRE TOMORROW?'
    Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979

  15. #15

    Thread Starter
    Member
    Join Date
    Sep 2003
    Posts
    47
    I used the SetStyle in either form load or sub new and it causes some graphics problem to the toolbar.

    Attached herewith is the screenshot:
    Attached Images Attached Images  

  16. #16
    Frenzied Member
    Join Date
    Oct 2002
    Location
    Gammapolis
    Posts
    1,474
    Add this to see if it resolves:

    SetStyle(ControlStyles.Opaque,True)
    'Heading for the automatic overload'
    Marillion, Brave, The Great Escape, 1994

    'How will WE stand the FIRE TOMORROW?'
    Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979

  17. #17

    Thread Starter
    Member
    Join Date
    Sep 2003
    Posts
    47
    No it doesn't help. The distortion still persists. Hmm..
    Anyway thanks for the great effort. Appreciated to all.

    Archaven

  18. #18
    Frenzied Member
    Join Date
    Oct 2002
    Location
    Gammapolis
    Posts
    1,474
    I tested here and there is no problem with toolbar, I am afriad thats because of you have XP visual styles enabled which is not the case here. Whould you please send me a sample so I test it here?
    'Heading for the automatic overload'
    Marillion, Brave, The Great Escape, 1994

    'How will WE stand the FIRE TOMORROW?'
    Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979

  19. #19

    Thread Starter
    Member
    Join Date
    Sep 2003
    Posts
    47
    Hi Lunatic, I've asked similar question on other boards and got a reply stating that the SetStyle function if instantiated on form load will only enable double buffering on the form itself - not the panel control.
    Hence it is advisable to subclass the panel control and called the SetStyle function in its constructor.
    I've tried subclassing the panel control and it works and it does not have the toolbar distortion.
    However, i have 2 panels in the form. The first panel acts as a frame which resizes when the form resized.
    The second panel which i called it a canvas basically being added to the 1st panel.
    I can't really debug where the problem is. When the program executes, the grids are not shown. It will only be shown when you scroll the scrollbars.
    Also, if you scroll quickly up and down, you will noticed that the grid is not properly drawn.
    Perhaps you can help? Attached herewith is the whole project.

    The file is quite small around 33Kb if you are using WinAce. But i compressed it using the ZIP format due to it's popularity but actually cause double of the ACE size.

    PS. You need to VSNET 2003 to open the project.

    Archaven
    Attached Files Attached Files

  20. #20
    Frenzied Member
    Join Date
    Oct 2002
    Location
    Gammapolis
    Posts
    1,474
    I tested your program. The problem is you are trying to paint in Paint event of the panel with a Graphics object that is different from e.Graphics and that is eventually repainted by e.Graphics and erased, so if you looked carefully it draws the grid and clear it. I recommend you to pass e.Grapihcs as the Graphics object to the the DrawGrid. The same happens when you resize the form in a way that the canvas is repainted and it clears all prevous objects that are drawn.
    Last edited by Lunatic3; Dec 2nd, 2003 at 03:57 AM.
    'Heading for the automatic overload'
    Marillion, Brave, The Great Escape, 1994

    'How will WE stand the FIRE TOMORROW?'
    Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979

  21. #21

    Thread Starter
    Member
    Join Date
    Sep 2003
    Posts
    47
    Hi Lunatic. Thank you very much. I was debugging it for awhile till i found out the solution. You are correct, when i pass e.graphics to the DrawGrid function everything function perfectly.

    Thank you for your great effort!

  22. #22
    Frenzied Member
    Join Date
    Oct 2002
    Location
    Gammapolis
    Posts
    1,474
    What about yuor DrawObject metohd?
    'Heading for the automatic overload'
    Marillion, Brave, The Great Escape, 1994

    'How will WE stand the FIRE TOMORROW?'
    Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979

  23. #23

    Thread Starter
    Member
    Join Date
    Sep 2003
    Posts
    47
    Yup. Fixed that as well. With the double buffering, it's freaking smooth! even with a large canvas size!

    I'm going to enhance it where you can drag any object and reposition/move it to any location. Also, i might try drawing those objects using GraphicsPath instead of direct drawing to the panel.

    In the meantime, any feedback for the program?

    There's a problem that i've noticed now. There's no keydown event for a panel control. I need it so that when user selected object(s) in the canvas and they can delete it by pressing the delete key from the keyboard.
    Anyway to resolve this by using the panel control?

    Archaven
    Last edited by Archaven; Dec 2nd, 2003 at 04:30 AM.

  24. #24
    Frenzied Member
    Join Date
    Oct 2002
    Location
    Gammapolis
    Posts
    1,474
    I liked to know if you used the e.Graphics to paint them too or not, as otherwise you would have problem with those too.
    And about the program, I dont know what is the primary goal of this program, but i liked your stylish way of coding.

    And for your problem, can't you use OnKeyDown ?
    Last edited by Lunatic3; Dec 2nd, 2003 at 04:37 AM.
    'Heading for the automatic overload'
    Marillion, Brave, The Great Escape, 1994

    'How will WE stand the FIRE TOMORROW?'
    Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979

  25. #25

    Thread Starter
    Member
    Join Date
    Sep 2003
    Posts
    47
    Yes. I've modified all the codes so that all drawing uses the e.Graphics from the OnPaint event.

    How do i use the OnKeyDown ? Where should i call it? Please enlight me.

  26. #26
    Frenzied Member
    Join Date
    Oct 2002
    Location
    Gammapolis
    Posts
    1,474
    It is one of the override methods of Panel class. So you can use it in your subclass of panel.
    'Heading for the automatic overload'
    Marillion, Brave, The Great Escape, 1994

    'How will WE stand the FIRE TOMORROW?'
    Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979

  27. #27

    Thread Starter
    Member
    Join Date
    Sep 2003
    Posts
    47
    Any codes or samples?

    Anyway do you know how to write a user-defined event?

    I've tried adding a keydown event to by subclass panel:

    Code:
    Public Class BufferedPanel
        Inherits System.Windows.Forms.Panel
    
        Public Sub New()
            SetStyle(ControlStyles.AllPaintingInWmPaint Or _
                    ControlStyles.DoubleBuffer Or _
                    ControlStyles.ResizeRedraw Or _
                    ControlStyles.UserPaint, True)
        End Sub
    
        Public Shadows Event KeyDown(ByVal e As KeyEventArgs)
    End Class
    And i've tried handling the KeyDown event by the subclassed panel:

    Code:
    Private Sub pnlCanvas_KeyDown(ByVal e As System.Windows.Forms.KeyEventArgs) Handles pnlCanvas.KeyDown
        If e.KeyCode = Keys.Delete Then
            'perform deletion
        End If
    End Sub
    The above codes shows no compile error. The weird thing is that it doesnt work/does not respond to the keydown event.

  28. #28
    Frenzied Member
    Join Date
    Oct 2002
    Location
    Gammapolis
    Posts
    1,474
    1- I doubt that piece of code compiles without error cause the method lacks 'Byval sender as Object'.

    2- Panel seems not to capture the keys cause it does not get focus. So to capture key you must first move focus to it.

    3-Even if you move focus to it, you can not capture 'Delete' key in that KeyDown Method. You have to use ProcessCmdKey, something like in the panel subclass:
    VB Code:
    1. Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, ByVal keyData As System.Windows.Forms.Keys) As Boolean
    2.       If keyData = Keys.Delete Then
    3.           'perform delete
    4.           Return True ' So it wont be passed to KeyDown Event
    5.       End If
    6. End Function
    or
    VB Code:
    1. Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, ByVal keyData As System.Windows.Forms.Keys) As Boolean
    2.       If keyData = Keys.Delete Then
    3.          Return False ' So the key is passed to KeyDown Event, and you perform delete there
    4.       End If
    5. End Function
    'Heading for the automatic overload'
    Marillion, Brave, The Great Escape, 1994

    'How will WE stand the FIRE TOMORROW?'
    Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979

  29. #29

    Thread Starter
    Member
    Join Date
    Sep 2003
    Posts
    47
    Hmmm.. one more last question. Are you a professor?
    You seem to know everything!

    Actually, i'm not from IT background. So don't be surprised if i ask silly question . I learn programming all by myself and sometimes by trial and error. I used to be a hardcore c++ coder. Not anymore now :P

    How about you?

  30. #30
    Frenzied Member
    Join Date
    Oct 2002
    Location
    Gammapolis
    Posts
    1,474
    No, I am not a prof or something, just a little more than a beginner. I have learned all the computer stuff by myself too. In fact I am a ...
    'Heading for the automatic overload'
    Marillion, Brave, The Great Escape, 1994

    'How will WE stand the FIRE TOMORROW?'
    Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979

  31. #31

    Thread Starter
    Member
    Join Date
    Sep 2003
    Posts
    47
    Hi Lunatic,

    I've added another parameter (sender by object) to the shadows event as well as the overrided ProcessCmdKey function as shown below:

    Code:
    Public Class BufferedPanel
        Inherits System.Windows.Forms.Panel
    
        Public Sub New()
            SetStyle(ControlStyles.AllPaintingInWmPaint Or _
                    ControlStyles.DoubleBuffer Or _
                    ControlStyles.ResizeRedraw Or _
                    ControlStyles.UserPaint, True)
        End Sub
    
        Public Shadows Event KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs)
    
        Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, keyData As System.Windows.Forms.Keys) As Boolean
            If keyData = Keys.Delete Then
                Return False
            End If
        End Function
    
    End Class
    Also, i've added the event handling for the OnKeyDown for the subclassed panel:

    Code:
        Private Sub pnlCanvas_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles pnlCanvas.KeyDown
            If e.KeyCode = Keys.Delete Then
                'perform deletion
            End If
        End Sub
    Regardless of ProcessCmdKey returns True/False, the KeyDown event does not fire. I've debugged it and found that the ProcessCmdKey works but it just that it didn't fire the KeyDown event of the subclassed panel.

    Where might be the possible error? And btw, I did set focus to the panel.

    Sorry for such a trouble!

    Btw, what are you then?
    Last edited by Archaven; Dec 2nd, 2003 at 09:40 PM.

  32. #32

    Thread Starter
    Member
    Join Date
    Sep 2003
    Posts
    47
    I think i found where the error was.
    It was the access level.

    Code:
    Public Shadows Event KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs)
    and the handling event:

    Code:
    Private Sub pnlCanvas_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles pnlCanvas.KeyDown
        If e.KeyCode = Keys.Delete Then
            'perform deletion
            MsgBox("test")
        End If
    End Sub
    by changing Public to Private seems to solve the problem. Anyway sorry for the trouble!

  33. #33
    Frenzied Member
    Join Date
    Oct 2002
    Location
    Gammapolis
    Posts
    1,474
    Whats the reason you use that, whether public or private? I don't know its usage.
    VB Code:
    1. Public Shadows Event KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs)
    Last edited by Lunatic3; Dec 2nd, 2003 at 10:10 PM.
    'Heading for the automatic overload'
    Marillion, Brave, The Great Escape, 1994

    'How will WE stand the FIRE TOMORROW?'
    Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979

  34. #34

    Thread Starter
    Member
    Join Date
    Sep 2003
    Posts
    47
    Yup, you are right. There are no reasons for its usage. I did that by trial and error. So sorry.

    Archaven

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width