BlElement >>drawStrokeOnAthensCanvas: aCanvas
"Actually render stroke of a receiver on aCanvas in local bounds. Override to customize. aCanvas is an instance of AthensCanvas aCanvas must not be nil" | pathTransform strokePath strokeScaling strokeOffset | "fast exit if stroke has no width or it is transparent" (self shape strokePaint width <= 0 or: [ self shape strokePaint isTransparent ]) ifTrue: [ ^ self ]. pathTransform := aCanvas pathTransform. strokePath := self shape path strokePathOn: aCanvas. strokeScaling := self shape path strokeScaling. strokeOffset := self shape path strokeOffset. pathTransform restoreAfter:[ pathTransform translateBy: strokeOffset * strokeScaling. pathTransform scaleBy: strokeScaling. aCanvas setPaint: self shape strokePaint; drawShape: strokePath ] BlElement >>drawFillOnAthensCanvas: aCanvas "Actually render fill of a receiver on aCanvas in local bounds. Override to customize. aCanvas is an instance of AthensCanvas aCanvas must not be nil" | pathTransform fillPath fillScaling fillOffset | pathTransform := aCanvas pathTransform. "fast exit if fill is transparent" (self shape fillPaint isTransparent) ifTrue: [ ^ self ]. fillPath := self shape path fillPathOn: aCanvas. fillScaling := self shape path fillScaling. fillOffset := self shape path fillOffset. pathTransform restoreAfter: [ pathTransform translateBy: fillOffset * fillScaling. pathTransform scaleBy: fillScaling. aCanvas setPaint: self shape fillPaint; drawShape: fillPath ] |
Hi Stef, Which build/version are you using? These methods are removed in the latest version. You can download the latest version from the Moose CI. From the bloc project you need the bleeding edge build. The link to this version is here: https://ci.inria.fr/moose/job/bloc/PHARO=alpha,VERSION=bleedingEdge,VM=vmLatest/ Cheers, Andrei On Mon, Apr 4, 2016 at 5:17 PM, stepharo <[hidden email]> wrote: BlElement >>drawStrokeOnAthensCanvas: aCanvas |
In reply to this post by stepharo
What is it? Why people so obsessed to overcomplicate everything? How drawFillOnAthensCanvas would look like, if you do things right? BlElement >>drawOnAthensCanvas: aCanvas ^ aCanvas draw: self shape. pfff.... On 4 April 2016 at 18:17, stepharo <[hidden email]> wrote: BlElement >>drawStrokeOnAthensCanvas: aCanvas Best regards,
Igor Stasenko. |
Hi,
Please take the latest version :). Cheers, Doru > On Apr 4, 2016, at 8:28 AM, Igor Stasenko <[hidden email]> wrote: > > What is it? > > Why people so obsessed to overcomplicate everything? > How drawFillOnAthensCanvas would look like, if you do things right? > > BlElement >>drawOnAthensCanvas: aCanvas > ^ aCanvas draw: self shape. > > pfff.... > > > On 4 April 2016 at 18:17, stepharo <[hidden email]> wrote: > BlElement >>drawStrokeOnAthensCanvas: aCanvas > "Actually render stroke of a receiver on aCanvas in local bounds. > Override to customize. > aCanvas is an instance of AthensCanvas > aCanvas must not be nil" > | pathTransform strokePath strokeScaling strokeOffset | > > "fast exit if stroke has no width or it is transparent" > (self shape strokePaint width <= 0 or: [ self shape strokePaint isTransparent ]) > ifTrue: [ ^ self ]. > > pathTransform := aCanvas pathTransform. > strokePath := self shape path strokePathOn: aCanvas. > strokeScaling := self shape path strokeScaling. > strokeOffset := self shape path strokeOffset. > > pathTransform restoreAfter:[ > pathTransform translateBy: strokeOffset * strokeScaling. > pathTransform scaleBy: strokeScaling. > aCanvas > setPaint: self shape strokePaint; > drawShape: strokePath ] > > > > > BlElement >>drawFillOnAthensCanvas: aCanvas > "Actually render fill of a receiver on aCanvas in local bounds. > Override to customize. > aCanvas is an instance of AthensCanvas > aCanvas must not be nil" > | pathTransform fillPath fillScaling fillOffset | > pathTransform := aCanvas pathTransform. > > "fast exit if fill is transparent" > (self shape fillPaint isTransparent) > ifTrue: [ ^ self ]. > > fillPath := self shape path fillPathOn: aCanvas. > fillScaling := self shape path fillScaling. > fillOffset := self shape path fillOffset. > > pathTransform restoreAfter: [ > pathTransform translateBy: fillOffset * fillScaling. > pathTransform scaleBy: fillScaling. > aCanvas > setPaint: self shape fillPaint; > drawShape: fillPath ] > > > > > -- > Best regards, > Igor Stasenko. -- www.tudorgirba.com www.feenk.com "To utilize feedback, you first have to acquire it." |
In reply to this post by stepharo
I saw in bleedingEdge it is different and looks better.
Now I was wondering why shape did not do the rendering and I thought that this is may be because a shape can be used for doing something else than rendering. For example clipping or as igor mentioned defining the shape of the interaction drawOnSpartaCanvas: aCanvas "Actually render receiver on aCanvas in local bounds. Override to customize. aCanvas is an instance of AthensCanvas aCanvas must not be nil" self assert: self shape path context isNotNil. aCanvas clipPreserveBy: self shape during: [ aCanvas paintGroup: [ aCanvas setPaint: self shape fillPaint. aCanvas fillPreserve. aCanvas paintMode source. aCanvas setStrokePaint: self shape strokePaint. aCanvas stroke ] ] unprotectedFullDrawOnSpartaCanvas: aCanvas "Draw the full structure on the given Canvas withing drawing bounds without caring about any errors and visibility. I am responsible for clipping and transforming canvas's path to local coordinates to allow simpler actual drawing in drawOnAthensCanvas: Additional checks should be implemented in fullDrawOnAthensCanvas: aCanvas is an instance of AthensCanvas. aCanvas must not be nil. @see BlElement>>#fullDrawOnAthensCanvas: @see BlElement>>#drawOnAthensCanvas:" self shape adaptTo: self. self shape path context: aCanvas. aCanvas transform: self transformation during: [ self clippingStrategy clip: self on: aCanvas during: [ self drawOnSpartaCanvas: aCanvas ] childrenDuring: [ self drawChildrenOnSpartaCanvas: aCanvas ] ] |
On 4 April 2016 at 19:00, stepharo <[hidden email]> wrote: I saw in bleedingEdge it is different and looks better. where i can download and look at this code?
Best regards,
Igor Stasenko. |
In reply to this post by stepharo
Hi,
Indeed, this was not clear. The original idea of the shape was to be primarily responsible for the clipping, but in the meantime the stroke and fill filtered in the implementation. Alex, Andrei and I will now change the “shape” to only be responsible for clipping and leave the drawing to the element. We will also propose a solution for dealing with drawing and interaction. Please stay tuned and thanks for this discussion. Cheers, Doru > On Apr 4, 2016, at 9:00 AM, stepharo <[hidden email]> wrote: > > I saw in bleedingEdge it is different and looks better. > Now I was wondering why shape did not do the rendering and I thought that this is may be because a shape can be used for doing something else > than rendering. For example clipping or as igor mentioned defining the shape of the interaction > > > > drawOnSpartaCanvas: aCanvas > "Actually render receiver on aCanvas in local bounds. > Override to customize. > aCanvas is an instance of AthensCanvas > aCanvas must not be nil" > > self assert: self shape path context isNotNil. > > aCanvas > clipPreserveBy: self shape during: [ > aCanvas paintGroup: [ > aCanvas setPaint: self shape fillPaint. > aCanvas fillPreserve. > aCanvas paintMode source. > aCanvas setStrokePaint: self shape strokePaint. > aCanvas stroke ] ] > > > > unprotectedFullDrawOnSpartaCanvas: aCanvas > "Draw the full structure on the given Canvas withing drawing bounds > without caring about any errors and visibility. I am responsible for > clipping and transforming canvas's path to local coordinates > to allow simpler actual drawing in drawOnAthensCanvas: > Additional checks should be implemented in fullDrawOnAthensCanvas: > aCanvas is an instance of AthensCanvas. > aCanvas must not be nil. > @see BlElement>>#fullDrawOnAthensCanvas: > @see BlElement>>#drawOnAthensCanvas:" > self shape adaptTo: self. > self shape path context: aCanvas. > > aCanvas > transform: self transformation > during: [ > self clippingStrategy > clip: self > on: aCanvas > during: [ self drawOnSpartaCanvas: aCanvas ] > childrenDuring: [ self drawChildrenOnSpartaCanvas: aCanvas ] ] > -- www.tudorgirba.com www.feenk.com "To utilize feedback, you first have to acquire it." |
In reply to this post by Igor Stasenko
Le 04/04/2016 18:56, Igor Stasenko a écrit :
> > where i can download and look at this code? > Hi Igor, Via Pharo Launcher under Moose Jenkins -> bloc. Or at https://ci.inria.fr/moose/job/bloc/ > > -- > Best regards, > Igor Stasenko. -- Cyril Ferlicot http://www.synectique.eu 165 Avenue Bretagne Lille 59000 France signature.asc (836 bytes) Download Attachment |
In reply to this post by Igor Stasenko
Nevermind, i found. Here some comments. Q. So, why you think i made Color to be polymorphic with Athens Paint protocol? A. Exactly to avoid producing extra entities like this: (BlColorPaint new color: (Color blue alpha: 0.5)) Because this BlColorPaint adds nothing , has no any extra information, no behavior.. Nothing. With Athens API any object can serve as paint, as long as it implements its protocol. What is rationale behind making BlPaint hierarchy? One more thing, i discovered at random chance: AthensSurface>>createShadowPaint: aColor "Answer an instance of AthensPaint, valid for use with given surface" What is this nonsense? I removed notion of shadow in old Canvas, just to see that someone introducing it in Athens? Okay, guys.. Do you realise that you polluting a base feature set with user-level feature. There is no 'shadow' as a concept in graphics framework. It is a user-level concept. Pff.. Shadow is thing you drawing on screen. It has nothing different from drawing anything else on screen from graphical engine perspective. Why you doing that ? You ripping me apart. BlShadowPaint. If you want to draw a shadow, don't call it paint. Just call it shadow. It has nothing to do with paint. I know it is convenient to put it that way and pretend that if you draw same shape with some offset and blur it slightly and use semitransparent color it will appear as a shadow. But it is not basic element or operation for any imaginable graphical engine. It is purely user-level feature, that should not pollute nor interfere with basic feature set. The main problem behind this 'shadows' in Canvas, that people were drawing full morph with 'shadow color' filter.. Now think you paint SystemWindow twice.. once for foreground, and second time for shadow.. with all its submorphs , etc, yadda yadda.. That's like shooting bacteria with earth-sized terrawatt laser. And you seem to like it.. and want to reintroduce.. In same horrible way as before. You have a shadow. Can i have a pony then? :) Best regards,
Igor Stasenko. |
Some more bashing today.. (don't take it personal, i may be wrong) BlPath hierarchy.. and BlShape. Why you redefining what is shape and what is path? Of course, you are free to do it in Bloc.. But in terms of Athens, all of BlPath are actually - shapes.. And BlShape is some kind of encapsulation of shape, paints and transform. It is a dumb state holder without any extra logic. My rule of thumb: do not produce dumb state holders. They has to be smart, else it makes no sense in creating separate entity and designating it as something else than any other bunch of data thrown into single clump, sitting there deaf, blind, dead and silent until someone else will grab it somewhere and start using it for own purpose. Sure, i could understand, why you potentially may want such object(s) around, but it is not shape anymore and i wouldn't call it like that. Because shape are shape, and has nothing to do with paints and transform, it don't knows and don't cares whether it will be filled or stroked or both, and how many times, and if there will be single paint or thousand. Such kind of properties is simply orthogonal to what shape existing for, because it exists only to define geometry. I think all of that came from not understanding the roles of objects and how they interact in Athens. Shapes define geometry. Paints define how that geometry will be filled/altered. The shapes and paints are related in a way that paints are used to fill shapes. But there's nothing tells that single shape can be filled only once with prescribed paint, and only then stroked.. or vise versa. The order and amount of operations, combinations and effects are up to the user. And they have to stay like so, if you don't intend to shrink feature set and hardwire, what users can do and what they cannot. I really hoping that you had no such intent. Be on your place, if you want to have a number of commonly used shapes, just make a factory class, so i can tell: CommonShapes rectangle: a@b to: c@d except, that Rectangle is a shape already.. and wrapping it with own class just adds more complexity, creating one extra beloved dumb state holder and nothing else. But i would imagine i could have: CommonShapes circle: 100@100 or CommonShapes roundedRectangle: 100@100 radius: 5 in any case, since there could be infinite number of 'possibly useful objects' when we talking about geometry.. your BlPath hierarchy will tend to grow and grow over time, ad infinity. Well, people love when there's order, like in that comic where guy painted 'cat' label on his cat, 'car' label on his car.. and all around in same way. Can't blame for that.. So, maybe. Whatever.. But your examples demonstating insane amount of bloat.. For example: exampleLine self new layoutStrategy: BlLinearLayout horizontal; layoutParamsDo: [ :lp | lp horizontal wrapContent. lp vertical wrapContent ]; addChild:(self new layoutParams: BlLinearLayoutParams new; shape: (BlShape new fillPaint: (BlColorPaint new color: (Color blue alpha: 0.5)); strokePaint: (BlStrokePaint new paint: (BlColorPaint new color: (Color green alpha: 1)); lineStyle: BlStrokeLineStyle new; width: 5); path: (BlLinePath new)); extent: 400 @ 200); openInWorld Guys, are you serious, you will find happy users, that is forced to produce so much code in order to draw a single, simple line on the screen? You must be kidding. I see that it is indeed comes from the requirement that BlElement can hot-swap its shape on the fly.. And so, you are forced to define all the properties and construct all the things in place. But there should be some sanity limit, where you should stop asking user for so much details. But if you want to go to such extreme, then all your examples would look like that: BlElement new content: (MyFancyPony new); openInWorld. Where MyFancyPony, is a content - an object that defines shape, and knows how to render itself and so on. A smart object, that knows how to behave and draw itself. Not just holding state. And number of properties and/or behavior is then up to the user. And he is free to use anything fancy or not to deliver content on the screen. That would be much better. But then it will duplicate the features of BlElement (or at least a significant subset of it) - being able to render itself. But still. P.S. Now i see BlElement.. why nobody said that it is replacement for Morph? I was thinking that in addition to BlMorph, you have BlElement :) Sure, you don't need two compositions. As long as there one thing that represent UI elements, that can form hierarchy its ok. So, i retract my comments about Elements.. And apologize. Best regards,
Igor Stasenko. |
In reply to this post by Tudor Girba-2
Doru
I have the impression that clipping and interaction can be defined by a "shape" then the drawing can be either drawn in a canvas or delegate to something else (for example for the cursor if there is an hardware rendering). I like this discussion and the feedback of igor because he is kicking our asses much better than me in fact because he has real argument while I just got feelings :) Stef Le 4/4/16 19:10, Tudor Girba a écrit : > Hi, > > Indeed, this was not clear. The original idea of the shape was to be primarily responsible for the clipping, but in the meantime the stroke and fill filtered in the implementation. Alex, Andrei and I will now change the “shape” to only be responsible for clipping and leave the drawing to the element. We will also propose a solution for dealing with drawing and interaction. > > Please stay tuned and thanks for this discussion. > > Cheers, > Doru > > >> On Apr 4, 2016, at 9:00 AM, stepharo <[hidden email]> wrote: >> >> I saw in bleedingEdge it is different and looks better. >> Now I was wondering why shape did not do the rendering and I thought that this is may be because a shape can be used for doing something else >> than rendering. For example clipping or as igor mentioned defining the shape of the interaction >> >> >> >> drawOnSpartaCanvas: aCanvas >> "Actually render receiver on aCanvas in local bounds. >> Override to customize. >> aCanvas is an instance of AthensCanvas >> aCanvas must not be nil" >> >> self assert: self shape path context isNotNil. >> >> aCanvas >> clipPreserveBy: self shape during: [ >> aCanvas paintGroup: [ >> aCanvas setPaint: self shape fillPaint. >> aCanvas fillPreserve. >> aCanvas paintMode source. >> aCanvas setStrokePaint: self shape strokePaint. >> aCanvas stroke ] ] >> >> >> >> unprotectedFullDrawOnSpartaCanvas: aCanvas >> "Draw the full structure on the given Canvas withing drawing bounds >> without caring about any errors and visibility. I am responsible for >> clipping and transforming canvas's path to local coordinates >> to allow simpler actual drawing in drawOnAthensCanvas: >> Additional checks should be implemented in fullDrawOnAthensCanvas: >> aCanvas is an instance of AthensCanvas. >> aCanvas must not be nil. >> @see BlElement>>#fullDrawOnAthensCanvas: >> @see BlElement>>#drawOnAthensCanvas:" >> self shape adaptTo: self. >> self shape path context: aCanvas. >> >> aCanvas >> transform: self transformation >> during: [ >> self clippingStrategy >> clip: self >> on: aCanvas >> during: [ self drawOnSpartaCanvas: aCanvas ] >> childrenDuring: [ self drawChildrenOnSpartaCanvas: aCanvas ] ] >> > -- > www.tudorgirba.com > www.feenk.com > > "To utilize feedback, you first have to acquire it." > > > |
In reply to this post by Igor Stasenko
Hi igor
I like your feedback. Could you summarize it based on the latest alpha version and now that you saw the code? In the bloc version you discussed with alain (in the house I was renovating) an element had a view that were responsibe of the rendering but it was not good. Stef Le 4/4/16 20:51, Igor Stasenko a
écrit :
|
In reply to this post by stepharo
Hi Stef, Currently there was a distinction between Shape and Path which turn out to be confusing. So Shape will go away and there will be just a Path (line, circle, rectangle, etc). We started to refactor this during the PharoDays. And yes, Rectangle will be polymorphic with Path. BlElement does support clipping and click detection by paths but right now they were implicit and you needed to subclass BlElement to override them independently. We'll change this so one can set them independently in BlElement. Yes, BlElement had a default path for drawing but that will go away. By default BlElement will have an empty drawOn... method. So to create a custom widget you can subclass BlElement, override drawOn... and use the canvas to draw anything you wish. There will be a subclass of BlElement that will add more drawing oriented logic but BlElement will be independent of that. Yes, the API of the canvas is not perfect but we're improving. Cheers, Andrei On Mon, Apr 4, 2016 at 6:00 PM, stepharo <[hidden email]> wrote: I saw in bleedingEdge it is different and looks better. |
In reply to this post by stepharo
On 4 April 2016 at 23:21, stepharo <[hidden email]> wrote:
My biggest source of concern, when i look at it is attempt to funnel features of Athens to obfuscate it down to the point that only simple, prescribed and rigid constructions will be possible. Athens is not perfect. As nothing is perfect. More than that: it proposing a quite limited subset of features comparing to other modern graphical engines. That's why i really surprised to see how people want to 'simplify' it even more, down to simplest possible constructs and throwing away the plethora of other possibilities. What was the point to make all those features, if you don't want to expose them to user? Or exposing them in a way, that most of them become hardly reachable. You cannot have a richer feature set than base engine provides, especially by shrinking that base.
I don't remember. The only view as a concept i can think of, we were discussing was a so-called 'viewport'. Is like defining a physical area on screen which are controlled by GUI, while other areas can be occupied by something else (be it other GUI kind, or 3D application etc). But in usual desktop, desktop covers whole screen and there seems like no huge outcry 'we need special views', so i would put it into 'good to have but not absolutely necessary' box.
Best regards,
Igor Stasenko. |
In reply to this post by stepharo
On 4 April 2016 at 23:17, stepharo <[hidden email]> wrote: Doru It is easy to kick asses.. much easier than doing things. And please, explain to guys, that i am not some kind of trolly crazy angry idiot, who sits in the corner making giggles and throwing paperballs into student(s), because its fun. It is because i also made similar mistakes, or have to fix other's mistakes at own time, and really don't want people repeating them over and over again, like ShadowCanvas, now its ShadowPaint. Stef Best regards,
Igor Stasenko. |
On Mon, Apr 4, 2016 at 11:45 PM, Igor Stasenko <[hidden email]> wrote:
yes, shadow should not be a paint. We discussed and decided to change that a few month ago just forgot to remove it. Cheers, Andrei
|
On 5 April 2016 at 00:51, Andrei Chis <[hidden email]> wrote: btw, Andrei , if you looking how you can test if point contains shape or not, take a look at AthensCurveFlattener. It converts curved path, that containing Bezier curves (or not) into simple polygonal shape that consists only from a simple lines. Then there AthensPolygonTester, that has the piece you missing: - a small algorithm that can test if given point inside or outside that polygon. Please note that it is simpler even-odd rule algorithm. It not works correctly for all possible cases. There's another algorithm- winding number algorithm, that is much better, but i had to switch to other stuff before were able to get my hands to it. It is more reliable, since it can work for self-intersecting shapes. So, what you need is to wire these things down to Bloc.Then whenever you need to test whether point within shape or not, you can convert any path into polygon and perform the test. And of course, you can cache the results of conversion in order to avoid expensive computations every time you need to perform such tests. Once path is converted, the test is relatively cheap and costs something like O(n), where n is number of line segments. Or maybe, to simplify things, you could extend the shape protocol and introduce #containsPoint: or as variant #containsPoint:ifNotAvailable: so that if shape implements such feature - it can answer true or false, and if not - evaluating a block. So, you don't have to implement all tests for all kinds of shapes that invented or not yet invented in universe. Best regards,
Igor Stasenko. |
On 5 April 2016 at 01:12, Igor Stasenko <[hidden email]> wrote:
Oh, forgot to add, you can look for example how i converting path in AthensBezier3Scene class.
Best regards,
Igor Stasenko. |
CONTENTS DELETED
The author has deleted this message.
|
On 5 April 2016 at 00:50, Anonymous <[hidden email]> wrote: As far as I know bloc already has perfect hit detection. In BlPath. What a Aha, i see - containsX: x Y: y render the path to determine if it contains point or not. Thank you for pointing out! Now i have another reason for yet another rant! Seriously, brute force is synonym of dumb. If you cannot solve the problem by anything else than using brute force, then first thing you do, you leave an extensive comment "sorry guys, this piece stinks, but i was <...> unable to do any better". That at least won't aflame people when they will look at it :)
Best regards,
Igor Stasenko. |
Free forum by Nabble | Edit this page |