Jump to content

aphillips

Members
  • Posts

    49
  • Joined

  • Last visited

Everything posted by aphillips

  1. If you can't afford a book try this book chapter on GDI+: http://codeproject.com/KB/books/1861004990.aspx
  2. I was going to post the source code to my changes but I have posted code on the forums before and I know that Rick (or whoever) prefers to write the code himself (but is amenable to the ideas, of course). This is good since the low-level design of my code is not that good So I will just describe what I did. (I can still provide the source, of course.) Line Corner Tool ---------------- The line corner toolbar drop-list was very easy to add. I just added the classes and code analogous to the Shape Draw drop-list (interior/outline/both). In ShapeTool.RenderShape I just set the outline pen line join type like this: outlinePen.LineJoin = AppEnvironment.LineJoin; instead of: outlinePen.LineJoin = LineJoin.MiterClipped; NOTE: There are 4 line corners options provided by GDI+ but I only allowed 3 (Round, Bevel and Miter). I did not provide a MiterClipped option as this provides a sharp corner (like Miter) but reverts to flat (Bevel) when the MiterLimit is reached. This gives an ugly jump between sharp and flat corners when adjusting a corner near the MiterLimit, whereas the Miter option provides a smooth change from sharp to clipped at the MiterLimit. I also considered, but did not provide an option for the user to set the MiterLimit value but instead hardcoded it at 2 (as before). Allowing larger values means that the way the outlineSaveRegion is calculated would have to change to allow for very sharp line corners that extend well beyond the line ends. DoubleClick ----------- I provided a DocumentDoubleClick event analogous to the DocumentClick event. This allows the user to terminate entry of polygons and polylines by double-clicking. Extra Nubs ---------- I provided several new nub shapes for scaling, rotating etc as well as for bezier nubs. I used the existing square nub for sharp corners on a polyline but added a round nub for smooth corners, and a diamond shape for bexier control points (also used for Line Tool). One useful thing was to add some primitive shape drawing functions (DrawSquare, DrawCircle, DrawCross etc) to the MoveNubRendered class that are combined to create more complex nub shapes in OnRender (depending on the nub type of course). Clicks ------ To allow for objects being created with multiple clicks I added a new (requiredClicks) member to the ShapeTool class to allow derived classes to say how many clicks they require. The meaning of the values are: -1: unlimited (eg Polyline tool) 0: single click including click-drag-release drawing (eg Freeform Shape Tool) 1: 2 clicks (eg rectangle where user clicks for both corners) 2: 3 click (eg triangle) etc To terminate an unlimited shape (requiredClicks == -1) the user can double-click or press Enter. The case of requireClicks == 0 is also handled specially. Only in this case are points accumulated (appended to the "points" array) while the mouse is being dragged - this allows all the points of a freeform shape to be retained. If requireClicks > 0 then the current mouse position replaces the last value of the "points" array rather than appending to it - in other words when the shape is finished the "points" array will only contain the actual points clicked. I also found I had to add a minimumClicks member to avoid things like creating a polygon with less than 3 points. RenderShapeBecauseOfEvent ------------------------- As the user can now change various shape options for all shapes derived from ShapeTool (while in scale/rotate/adjust modes) I added a RenderShapeBecauseOfEvent handler to this class. This is similar to the same handler for LineTool but also handles: - ShapeDrawTypeChanged - since (unlike LineTool) some shapes can be filled - LineJoinChanged - to handle new LineJoin control (above) ShapeDrawMode ------------- Before my changes when a shape tool was active the user could either be creating a shape or not creating one. Basically this was kept tracked of by the "mouseDown" private member. I expanded on this by adding the shapeDrawMode (enum) which could take these values: NotDrawing, // finished/not yet started Clicking, // drawing initial shape Scale, // shape can be scaled in X, Y or both Scaling, // shape is being scaled (handle is being dragged) Rotate, // shape can be rotated or skewed or centre of rotation moved Rotating, // one of the rotate/skew handles is being dragged Adjust, // shape can be adjusted using original click points (+ beziers for polyline) Adjusting, // one of the adjust handles is being dragged LineTool -------- The ShapeTool base class does a lot with nubs that previously only LineTool did. To avoid duplicating too much code I moved some of the code around. This stuff was a bit tricky. I created new virtual functions that are overridden in LineTool: - OnPulse - UpdateAdjustNubs I removed inCurveMode which is now handled by the base class ShapeDrawMode protected member. Mouse and Keyboard ------------------ There was a lot of changes to OnStylusDown, OnStylusMove, OnMouseMove, OnStylusUp to handle various modes mentioned above. They are fairly straightforward bu I can provide the source code. In the Scale/Rotate/Adjust modes the use can switch to the next mode by clicking inside the bounding box but not on a nub. I also allowed the use to click on the centre transform nub to switch to the next mode as long as they don't drag it more than 2 (screen) pixels. I needed to add som special flag variables that are set in the derived class constructors to disallow some modes - eg FreeformShapeTool does not allow Adjust mode. I also added an OnDoubleClick handler to allow finishing of polygons/lines when in Clicking mode. I also added an OnKeyPress handler to allow Enter to finish polygons/lines. Pressing Enter when scaling etc finalises the shape in the design, or pressing the Esc key removes the shape. Note that Esc key leaves the shape as it is and calls HistoryStack.StepBackward() to get rid of it - this make the change re-doable (Ctrl+Y) which seems to be the convention in PDN. Transforms ---------- To handle the affine transforms (moving, scaling, rotating, skewing) I added a private System.Drawing.Drawing2D.Matrix member. This is initially I, but stores any manipulations of the transform nubs. This matrix is used to render the shape and is also needed when adjusting nubs after the shape has been transformed. To render the shape properly I created CreateTransformedPath which is called in RenderShape (instead of CreateShapePath). All it does is call the derived CreateShapePath to get the point then transforms them using PdnGraphicsPath.Tranform(matrix). It also displays info in the status bar about the current transform being done if in Scaling/Rotating/Adjusting mode. Care is needed to apply the matrix to screen points when checking if the mouse is over a nub, dragging nubs, drawing nubs in the correct position. You also need to invert the matrix (Matrix.Invert()) when converting screen coordiantes to transformed shapes coordinates. One thing to watch is that Matrix.Rotate takes an angle in degrees rather than radians as expected. It is also counter-clockwise from the X axis rather than clockwise from the Y-axis (as is normal for angles in degrees). Polygon Tool ------------ The polygon tool is almost identical to the FreeformShape tool except that requiredClicks is set to -1. Polyline Tool ------------- The Polyline tool started out very similar to the Line Tool. The main difference being that it had a set of nubs that varied depending on the number of line segments. When I added the sharp and smooth segment joins it became even more tricky. First, I used the "points" array to store the line segements but also the bezier points - this required making sure that the number of points is always 1 modulus 3 (ie 4,7,10,13, ...) otherwise GDI+ AddBeziers call complains. I also needed to add a new array to keep track of which joins were sharp and which were smooth. Finally I also had to add some virtual functions to ShapeTool and override them in PolylineTool to allow the nubs to be drawn and dragged properly in "Adjust" and "Adjusting" modes.
  3. I was aware of this (and barkbark00 also mentioned it). The same happens for any constrained shape - square, line at fixed angles etc. (I consider it a feature since you might change your mind later Its probably not that hard to fix, but I don't have time now. The workaround is to hold down shift when the shape is "finalised" in the bitmap - ie when you click outside the shape, select a different tool etc.
  4. One more thing - I put my strings in PaintDotNet.Strings.3.resources but not in the translations. I suspect the patched version will crash if you use anything but English.
  5. OK I have fixed all known bugs and put the new files in the same location. http://expertcomsoft.com/Downloads/PDNAP.zip
  6. I found another bug. When you drag nubs of a polyline it draws nearby nubs as you drag so you can see what is happening. However, these nubs are drawn in untransformed coords, so if you have scaled, rotated etc then they are drawn in the wrong place. As a few people want to use this patch I will fix the bugs and provide an update.
  7. > 2. It has a few rough edges. Also the pulsating nubs work well for the simple shapes but if you have a long polyline it looks like a string of Christmas lights! A bit overwhelming.
  8. Sorry, I only just got back to read the replies. Just a few notes on my changes: 1. First this was just a demonstration of enhancements that I think should be added to PDN. (I actually suggested allowing affine transformations years ago in the forums.) I thought an actual demonstration would show its usefulness, rather than harping on about it. These changes were never intended to be incorporated into PDN as is, and should not be. Rick can better decide how/if/when they should be done. For example, the polyline tool and the line tool are probably better combined somehow. 2. It has a few rough edges. The nub shapes I made are pretty ordinary. Also I was aware of the problem with constrained shapes that barkbark00 pointed out but forgot to mention it. It should be addressed. 3. Bugs. I originally modified the code to draw shapes using my preferred method of a click for each point. (Ie drawing the basic shapes requires 2 clicks instead of click-drag-release.) This is also more consistent with how polygons/polylines are drawn which require more than just 2 points. However I took that change out just at the last moment to keep the changes compatible with what everyone is used to in the official release. Unfortunately, this caused bugs such as the problem with the line tool that Ash pointed out and the crash that Bobofthedead and other found. 4. As Rick mentioned I did not fill in the email, forum etc strings in the source code. I (perhaps stupidly) just took out the markers so it would build, leaving the strings empty. I think (haven't tried it) that this means it will just crash if you use facilities that send email, go to the forums etc. 5. I am more than happy to provide the source code. (I just didn't provide it as I read somewhere that unsolicited code is not accepted.) 6. This is a patch designed for PDN 3.10 only. I think I did disable the automatic updates code so it will not wipe out the patch unexpectedly. If you want to use it, it's probably best to install 3.10, then patch it, then copy the whole directory elsewhere. Then uninstall, and re-install the official PDN 3.10 so you have the official version and can get updates.
  9. Hi glacialfury, I had a look recently at how layers are rendered in PDN and although by no means an expert I have perhaps delved a little deeper than you and may provide some insight. First I must point out that the software is not that large and although it uses some advanced techniques it is amazingly simple to fathom once you understand the overall design. Of course, it could stand some high-level design documentation for the many people who appear to be interested in studying it. But back to your question ... First you must understand that each layer is stored separately. (Each Document contains a LayerList which is an ArrayList of Layers. Currently all Layers are of the same derived type BitmapLayer. A BitmapLayer contains a Surface which contains the actual pixels of the layer.) When you use the eraser you are simply putting transparent pixels onto the active layer so that whatever is below (a layer below or the background) shows through. When you erase (or draw something) you only change the active layer which is immediately combined with the other layers to be rendered on the screen. (The rendering of a layer occurs in BitmapLayer.RenderImpl which is called for each layer from Document.Render. After that other "decorations" not part of the actual design are rendered like nubs, selection, grid etc.) I hope this helps.
  10. One thing I always wanted in PDN was to be able to rotate shapes. GDI+ has such great support for affine transformations (rotate, scale etc) that it seemed it would be easy to do this and a shame not to. (I always though it pathetic that earlier versions of Windows could only draw ellipses, rectangles, text etc parallel to the X and Y axes.) A couple of years ago I actually added the ability to apply affine transformations to shapes, before they were "finalised" in the bitmap (in PDN 2.1). This used the fairly standard mechanism of "handles" (also sometimes called "control points") to allow transformations: 1. Initially 4 handles on the sides of object bounding rectangle that allowed scaling in X or Y 2. Handles on corners that allowed proportional scaling in X and Y together 3. Center handle that allowed moving (translating) the object unchanged 4. Click anywhere else in the bounding box to go from "scaling" mode (above) to "rotating" mode 5. In rotate mode, handles on the 4 corners are provided to rotate the object to any angle 6. The center handle moves the center of rotation 7. Handles on the four sides for skew 8. Click anywhere else in the bounding box to go into "adjusting" mode 9. Handles for original clicked points to adjust the shape (eg the 2 corners for a rectangle) 10. Click any where else in the bounding box to go back to "scaling" mode 11. Click outside the bounding box to "finalise" the shape This was fairly easy to do in PDN 2.1. The main problem was drawing the handles in XOR mode for which I had to go to the Windows API (since GDI+ does not support drawing in XOR mode for some reason). PDN 3.10 --------- With the release the much improved (MDI!) PDN 3, I thought it was time to port the above changes. I was pleasantly surprised to find the "nub" system which I could easily extend and do away with my ugly "handles" and Windows API calls. I managed to port my changes to 3.10 in a few hours and they worked very well. Encouraged by this I then implemented Polygon and Polyline tools. The polygon tool is much like the freeform shape tool but only adds points to the shape whenever the user clicks the mouse, joining them with straight lines. The polyline tool is similar but is not a closed shape and hence cannot be filled. This took even less time so I then added a new toolbar corner type drop-down list which allowed control of the shape of line corners (ie how 2 line segments are joined together). This control gives the option of rounded, flat, or clipped (sharp corners which are clipped if the angle is too acute). [Currently in PDN 3.10 line corners are always sharp but revert to flat (not clipped) if they become too acute. The effect is not often seen with current shapes (but can be seen in the freeform shape or a very flat ellipse, ...?) but with the ability to have polygons, polylines and skewed rectangles control of line joins becomes important.] Further encouraged by this I added full bezier support to polylines. This allows either sharp joins by left-clicking (which use the above-mentioned line corner control) or smooth joins by right-clicking. As in other programs adjusting the bezier handle at a smooth join moves the opposing bezier diametrically opposite in order to preserve the perfectly smooth join. Also polylines also support the line styles (dash etc) as well as line caps (rounded, arrow etc) which was added for the line tool in 3.10. I was amazed at how simple it was to make these improvements and how useful these features are. Not only can you rotate, scale, etc and adjust the shape of object (eg corners of the rectangle or polygon), you can also adjust any other of the shape drawing parameters (brush width, fills, line ends, anti-aliasing etc) before the shape is "finalised". Try it ----- If you want to try the changes you can download a zip file from Edit by Rick: download link removed, see last post and just copy the files over the corresponding files after installing Paint.Net 3.10. (Of course, you should keep a copy of the original files before overwriting them.) Then run PaintDotNet.exe as normal. See below an actual screen capture highlighting these features. This was annotated with PainDoNet (of course) using the new arrow line caps feature: Future ------ There are still a few more things I have thought of which I have not yet had time to do, but these would be easy judging by my above experience. 1. Bezier support to polygons (just like in polylines). 2. The ability to rotate text would be useful. 3. Control of rounding radius for rounded rectangles. 4. Constrain angles of polygon/line to make it easy to draw shapes like a right-angle triangle. 5. Better polyline bezier "nubs" that indicate which corner they are associated with Thanks ------- Thanks to Rick et al for making the source available and creating software that is so incredibly easy to modify.
  11. I was thinking more like: FFFF0000red FF00FF00green ; etc [quote] The implication (which I should have stated) is that the color name would appear in a tip window when the mouse hovers over a swatch. > .. covering an existing un-required colour with white .. A workaround but it doesn't delete it - it just makes it white.[/quote]
  12. Yes, I have been editing the .TXT files but it is a bit hard to work out which color is which. If I could put a color name next to the ARGB value it would be easier. My initial impulse was just to grab them and drag them around. This seems intuitive to me but may not be to others.
  13. The new color swatches are very nice. A small thing is that after selecting a color by clicking on a swatch it would be very convenient if the one clicked remained highlighted somehow. I was adjusting several shades of red that were already in a palette and found it difficult to remember which one I was working on (ie which swatch to put the color back into). One thing I find frustrating is that you can't organise the swatches the way you want. There is no way to re-order or delete. I know you removed the delete button (and why). My own suggestion is to be able to drag any button to move it to a different position (and/or "select" it and use the arrow keys) or completely drag it outside the swatch area to delete it (and/or "select" it and press the Del key). I also think that when adding a color it might be more obvious if clicking the add button simply adds the new swatch to the start of the list and "selects" it - the user can then move it where they want it. This addresses the concerns expressed in http://paintdotnet.12.forumer.com/viewt ... our+pallet too. It would also be useful (not essential) to be able to give names to colors, even if this was just by manually editing the text file. Also do you intend to be able to read other palette file types (.COL, .CLR, .PAL)?
  14. There was supposed to be a special text layer at one stage which allowed text to be editable. I guess it got dropped.
  15. What you say makes sense mathematically (after my brain starts working) and obviously avoids problems/inconsistencies in the code. Thanks for the explanation. FYI I am editing and saving in .PNG in case we can use alpha channel later. The actual images are currently loaded as .BMP. But I wanted to save the background as (0,192,192,192) in .PNG to allow easy/automatic conversion to .BMP. BoltBait's workaround of (1,192,192,192) works fine. (Another idea would be to be able to specify the RGB value for transparent areas when saving to .BMP??) Thanks again for all replies.
  16. void Render(Surface dst, Surface src, Rectangle rect) { ColorBgra PixelColor; for(int y = rect.Top; y < rect.Bottom; y++) { for (int x = rect.Left; x < rect.Right; x++) { PixelColor = src[x, y]; if (PixelColor.A == 0) { PixelColor.A = 1; PixelColor.R = PixelColor.G = PixelColor.B = 192; } dst[x, y] = PixelColor; } } }
  17. (1,192,192,192) Thanks!! Why didn't I think of that?
  18. I might further explain that I want to keep the transparency in the images so that it may be used in the future. But I want the images to work now, when the alpha channel is ignored.
  19. I have a follow-on question but first a bit of background: I am trying to use images with alpha channel in a toolbar in an dev. environment where the alpha channel is ignored. (The above question was so that I could easily see the effect in PDN to adjust them when required.) The next problem is that the transparent colour for the buttons is hard-coded with RGB values of (192,192,192 - light gray). Currently the completely transparent areas seem to be black (0,0,0). I can fill them with (0,192,192,192 - transparent light gray) but it PDN seems to keep reverting these back to (0,0,0,0 - transparent black). How do I get the right background color?
  20. Actually I just remembered Code Lab. Never tried it before but it was so easy. Here is my code: void Render(Surface dst, Surface src, Rectangle rect) { ColorBgra PixelColor; for(int y = rect.Top; y < rect.Bottom; y++) { for (int x = rect.Left; x < rect.Right; x++) { PixelColor = src[x, y]; //if (PixelColor.A > 0) PixelColor.A = (byte)(255); dst[x, y] = PixelColor; } } }
  21. Is there a simply way to remove transparency? Ie change the alpha value of all pixels in a layer to 255 but leave the RGB unchanged.
  22. > http://www.eecs.wsu.edu/paint.net/roadmap.htm This link doesn't work but http://www.eecs.wsu.edu/paint.net/roadmap.html does. > http://www.eecs.wsu.edu/paint.net/faq.htm This link also doesn't work.
×
×
  • Create New...