Skip to content

Commit 53e1de2

Browse files
committed
2 parents 211648e + 47b3f54 commit 53e1de2

File tree

13 files changed

+568
-66
lines changed

13 files changed

+568
-66
lines changed

Chapters/Alexandrie/alexandrie.md

Lines changed: 152 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ The path expresses the shape you want to draw with a virtual pen. It's then appl
141141
to the destination using the `paint` message.
142142

143143
It's expressed with simple primitives:
144+
144145
* `moveTo:` moves to the specified location.
145146
* `relativeMoveTo:` moves to the specified location, relative to your starting point.
146147
* `lineTo:` adds a line to a specified location.
@@ -153,6 +154,7 @@ It's expressed with simple primitives:
153154
You can find more methods in the class `AeCairoContext`.
154155

155156
#### Example.
157+
156158
Here is a full example which results in Fig. *linepath*.
157159

158160
```smalltalk
@@ -243,7 +245,7 @@ context
243245

244246
### Color
245247

246-
You can select different color styles to paint your path: a color, a linear gradient, a radial gradient and a bitmap.
248+
You can select different color styles to paint your path: a color, a linear gradient, a radial gradient a bitmap and a mesh gradient.
247249

248250
#### Single color.
249251

@@ -253,6 +255,10 @@ context sourceColor: (Color yellow alpha: 0.2);
253255

254256
#### Linear gradient.
255257

258+
Generally speaking, a gradient is a smooth transition of colors defined by two
259+
or more stop-colors. In the case of a linear gradient, this transition is defined
260+
by a straight line.
261+
256262
```smalltalk
257263
gradient := AeCairoLinearGradientPattern
258264
from: 0 @ 0
@@ -265,6 +271,16 @@ context source: gradient;
265271

266272
#### Radial gradient.
267273

274+
In the case of a radial gradient, the transition is defined by a center and a
275+
radius, between the two circles defined by innerCirle and outer circle
276+
Colors expand evenly in all directions from the inner center of the inner circle
277+
to outside of the outer circle. Before using the gradient pattern, a number of
278+
color stops should be defined
279+
280+
The coordinates here are in pattern space. For a new pattern, pattern space is
281+
identical to user space, but the relationship between the spaces can be changed
282+
with `AeCairoPattern >> matrix:`.
283+
268284
```smalltalk
269285
gradient := AeCairoRadialGradientPattern
270286
innerCenter: 50 @ 50
@@ -277,15 +293,88 @@ gradient := AeCairoRadialGradientPattern
277293
context source: gradient.
278294
```
279295

280-
#### Bitmap.
296+
### Mesh gradient
297+
298+
A mesh gradient is defined by a set of colors and control points. The most basic
299+
type of mesh gradient is a Gouraud-shading triangle mesh.
300+
301+
```smalltalk
302+
| aSurface aContext aMeshPattern |
303+
aSurface := AeCairoImageSurface extent: 100 @ 100.
304+
aContext := aSurface newContext.
305+
306+
aMeshPattern := AeCairoMeshPattern new.
307+
aMeshPattern
308+
beginPatch;
309+
moveTo: 50 @ 0;
310+
lineTo: 100 @ 100;
311+
lineTo: 0 @ 100;
312+
cornerColors: {
313+
Color red alpha: 0.5.
314+
Color green.
315+
Color blue };
316+
endPatch.
317+
318+
aContext
319+
sourceColor: Color yellow;
320+
paint;
321+
source: aMeshPattern;
322+
paint.
323+
324+
^ aSurface
325+
```
326+
327+
A more sophisticated patch of mesh gradient is a Coons patch. A Coons patch is
328+
a quadrilateral defined by 4 cubic Bézier curve and 4 colors, one for each vertex.
329+
A Bézier curve is defined by 4 points, so we have a total of 12 control points
330+
(and 4 colors) in a Coons patch.
331+
332+
```smalltalk
333+
| aSurface aContext aMeshPattern |
334+
aSurface := AeCairoImageSurface extent: 150 @ 110.
335+
aContext := aSurface newContext.
336+
337+
aMeshPattern := AeCairoMeshPattern new.
338+
aMeshPattern
339+
beginPatch;
340+
moveTo: 45 @ 12;
341+
curveVia: 69 @ 24 via: 173 @ -15 to: 115 @ 50;
342+
curveVia: 127 @ 66 via: 174 @ 47 to: 148 @ 104;
343+
curveVia: 65 @ 58 via: 70 @ 69 to: 18 @ 103;
344+
curveVia: 42 @ 43 via: 63 @ 45 to: 45 @ 12;
345+
cornerColors: {
346+
Color red.
347+
Color green.
348+
Color blue.
349+
Color red alpha: 0.5 };
350+
endPatch.
351+
352+
aContext
353+
sourceColor: Color yellow;
354+
paint;
355+
translateByX: -15 y: 0;
356+
source: aMeshPattern;
357+
paint.
358+
359+
^ aSurface
360+
```
361+
362+
#### Bitmap and PNG file.
281363

282364
```smalltalk
283365
form := AeCairoImageSurface fromForm:
284366
PolymorphSystemSettings pharoLogoForm.
285367
context sourceSurface: form x: 0 y: 0
286368
```
287369

288-
The `stroke` and `fill` messages with use the source color specified and apply itto your path.
370+
You can also get your surface from external files.
371+
372+
```smalltalk
373+
aSurface := AeCairoImageSurface newFromPngFileAt: 'a.png' asFileReference.
374+
aSurface inspect
375+
```
376+
377+
The `stroke` and `fill` messages will use the source color specified and apply it to your path.
289378

290379
Figure *@colorpaint@* presents a full example with all color possibilities.
291380

@@ -301,8 +390,37 @@ destination, by manipulating the transformation matrix.
301390
* `rotateByRadians:` modifies the current transformation matrix by rotating the user-space axes by angle radians.
302391
* `setIdentityMatrix` resets the current transformation matrix by setting it equal to the identity matrix.
303392

393+
### composition operator
394+
395+
Normally, you will be using Alexandrie to draw objects on top of each other. But Alexandrie can do differently, if you need it! In fact, you can use all the compositing operators.
396+
397+
In the example below, we'll have two rectangle, one red and one blue, on top
398+
of each other. Depending of the compositing operator used, the result will be
399+
completely different.
400+
401+
This is the code for the **clear** operator. You can change it to all other operator
402+
available. Some are directly available at the context level, but for the majority
403+
of them, you need to specify the context operator.
404+
405+
```smalltalk
406+
| surface context |
407+
surface := AeCairoImageSurface extent: 150 @ 120 format: AeCairoSurfaceFormat argb32.
408+
context := surface newContext.
409+
context sourceColor: Color transparent; paint.
410+
411+
context sourceColorR: 0.7 g: 0 b: 0 a: 0.8; rectangle: (0 @ 0 extent: 120 @ 90); fill.
412+
413+
context operator: AeCairoOperator clear.
414+
"or context setOperatorClear"
415+
416+
context sourceColorR: 0 g: 0 b: 0.9 a: 0.4; rectangle: (40 @ 30 extent: 120 @ 90); fill.
304417
305-
### Mask and clip
418+
^ surface asForm
419+
```
420+
421+
![all cairo operators.](figures/all_cairo_operators.png width=60&label=mask)
422+
423+
### Mask
306424

307425
The `mask` operations allow transfer according to the transparency/opacity of
308426
a second source pattern or surface. Where the pattern or surface is opaque,
@@ -330,6 +448,9 @@ The `clip` establishes a new clip region by intersecting with the current path
330448
by effectively masking out any changes to the surface that are outside the
331449
current clip region.
332450

451+
Like *stroke* or *fill*, the *context* will forget your path once applied.
452+
If you want to keep it for *clip* operations, you should use the `clipPreserve` messages.
453+
333454
In the following snippet, we clip a circle in the middle of our picture which only shows part of the Pharo logo (as shown in Fig. *@clip@*).
334455

335456
```smalltalk
@@ -352,11 +473,36 @@ context paint.
352473

353474
![Example of clip.](figures/clip.png width=60&label=clip)
354475

476+
### Drawing on other surfaces
477+
478+
So far in this chapter, we have been only using *AeCairoImageSurface* to draw our
479+
elements. Alexandrie, being based on Cairo graphics library, provide alternatives
480+
drawing surface that could be used in your project:
481+
482+
* *AeCairoPDFSurface* to generate PDF (Portable Document Format) file.
483+
* *AeCairoSVGSurface* to generate SVG (Scalable Vector Graphics) files.
484+
485+
Targeting external files, they can be used just like *AeCairoImageSurface* with the following differences:
486+
487+
1. On instance creation, the user specifies
488+
1. output filename (as String)
489+
2. the extent in points (1 point == 1/72.0 inch).
490+
2. When drawing is done, the user should send #finish to write the file trailer into the library buffer and then flush to disk.
491+
492+
Please not that before `#finish`, the file may already exist in disk with 0 bytes.
493+
If the garbage collector finalizes the instance before `#close`, the exported file
494+
may have an invalid format.
495+
496+
References:
497+
* http://zetcode.com/gfx/cairo/cairobackends/
498+
* http://www.ie.u-ryukyu.ac.jp/~e085739/c.cairo.3.html
499+
* https://cairographics.org/manual/cairo-PDF-Surfaces.html
500+
* https://cairographics.org/manual/cairo-SVG-Surfaces.html
355501

356502
### Conclusion
357503

358-
Alexandrie is the foundation for the graphics Pharo layer. In addition, it lets
359-
the programmer draws low-level graphics.
504+
Alexandrie is the foundation for the graphics Pharo layer. In addition, it lets
505+
the programmer draws low-level graphics or create external PDF or SVG files.
360506

361507

362508

33.6 KB
Loading

Chapters/Attic/BlocForPharoByExample13Book.md

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ All of the objects that you see on the screen when you run Pharo are
1111

1212
The class `BlElement` itself is a large class with many methods; this makes it
1313
possible for subclasses to implement interesting behavior with little code. You
14-
can also customize an element directly. Contrary to the old Morphic environment,
15-
Bloc favors much more object composition over inheritance.
14+
can also customize an element directly. Unlike the old Morphic environment, Bloc strongly favors object composition over inheritance.
1615

1716
To create a BlElement to represent a string object, execute the following code in a Playground.
1817

@@ -46,8 +45,8 @@ object in Pharo: by sending messages, we can change their
4645
properties, create new subclasses of Morph, and so on.
4746

4847
Every bloc element, when opened on the screen has a position and a
49-
size. If they are irregularly shaped, their position and size are
50-
those its *bounds*.
48+
size. If it is irregularly shaped, its position and size are
49+
determine by its *bounds*.
5150

5251
- The `position` method returns a `Point` that describes the location of the bloc element upper-left corner of its bounding box. The origin of the coordinate system is the parent's upper left corner, with *y* coordinates increasing *down* the screen and *x* coordinates increasing to the right.
5352
- The `extent` method also returns a point, but this point specifies the width and height of the bloc element rather than a location.
@@ -135,7 +134,7 @@ some mouse interaction.
135134

136135
To build live user interfaces using bloc elements, we need to be able to
137136
interact with them using the mouse and keyboard.
138-
Moreover, the element needs to be able to respond to user input by changing their appearance and position -- that is, by animating themselves.
137+
Moreover, the elements need to be able to respond to user input by changing their appearance and position -- that is, by animating themselves.
139138

140139
Let's extend our cross element to handle mouse events. Suppose that when we
141140
enter on the cross, we want to change the color of the cross to red, and when
@@ -328,8 +327,7 @@ cross requestFocus.
328327

329328
### Drag-and-drop
330329

331-
Bloc has also basic support for drag-and-drop which needs to be further
332-
improved. In the coming example, if you change the order of appearance of the
330+
Bloc has also basic support for drag-and-drop which requires further improvement. In the coming example, if you change the order of appearance of the
333331
elements, drag&drop may not work - element will not catch the appropriate event.
334332
This example will however show all events used with a working example.
335333

@@ -693,4 +691,4 @@ self addEventHandler: (BlEventHandler
693691
694692
```
695693

696-
Now the die will roll or stop rolling when we click on it.
694+
Now the die will roll or stop rolling when we click on it.

Chapters/bloc/element.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,40 @@ BlElement new
251251

252252
![Background color.](figures/backgroundcolortype.png width=80)
253253

254+
#### Element background and geometry tricks
255+
256+
In general is the geometry (and also the transformation matrix) doesn't change
257+
the BlElement size. The opposite, in general the geometry takes into account the
258+
element's size (via matchExtent:). But this is not the case for polygon or polyline...
259+
260+
If you don't pay attention to this, you can have a linear gradient that doesn't
261+
cover all your element, as illustrated by:
262+
263+
```smalltalk
264+
BlElement new geometry: (BlPolygonGeometry vertices: { (100 @ 0). (200 @ 0). (300 @ 100). (0 @ 100) });
265+
background: (BlLinearGradientPaint vertical from: Color black to: Color white);
266+
border: (BlBorder paint: Color red width: 3).
267+
```
268+
269+
![Wrong geometry size.](figures/geometry_size_painting.png width=80)
270+
271+
Obviously, the white part take too much space. To fix this, you need to specify
272+
the size of your element, from the size of its geometry. Like:
273+
274+
```smalltalk
275+
aGeometry := BlPolygonGeometry vertices: {(100 @ 0). (200 @ 0). (300 @ 100). (0 @ 100) }.
276+
277+
BlElement new geometry: aGeometry;
278+
size: aGeometry geometryBounds extent;
279+
background: (BlLinearGradientPaint vertical from: Color black to: Color white); border: (BlBorder paint: Color red width: 3);
280+
yourself
281+
```
282+
283+
This will render as expected:
284+
285+
![Wrong geometry size.](figures/geometry_size_painting_right.png width=80)
286+
287+
254288
### Element effect
255289

256290
You can get the list of all the effects available by executing: `BlElementEffect allSubclasses`

0 commit comments

Comments
 (0)