2 * Copyright 2010-2013, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT license.
6 * Deyan Genovski, deangenovski@gmail.com
7 * Geoffry Song, goffrie@gmail.com
16 #include <AffineTransform.h>
18 #include <GradientLinear.h>
24 #undef B_TRANSLATION_CONTEXT
25 #define B_TRANSLATION_CONTEXT "Leaves"
28 // path data for the leaf shape
29 static const BPoint
kLeafBegin(56.24793f
, 15.46287f
);
30 static BPoint kLeafCurves
[][3] = {
31 { BPoint(61.14, 28.89), BPoint(69.78, 38.25), BPoint(83.48, 44.17) },
32 { BPoint(99.46, 37.52), BPoint(113.27, 29.61), BPoint(134.91, 30.86) },
33 { BPoint(130.58, 36.53), BPoint(126.74, 42.44), BPoint(123.84, 48.81) },
34 { BPoint(131.81, 42.22), BPoint(137.53, 38.33), BPoint(144.37, 33.10) },
35 { BPoint(169.17, 23.55), BPoint(198.90, 15.55), BPoint(232.05, 10.51) },
36 { BPoint(225.49, 18.37), BPoint(219.31, 28.17), BPoint(217.41, 40.24) },
37 { BPoint(227.70, 26.60), BPoint(239.97, 14.63), BPoint(251.43, 8.36) },
38 { BPoint(288.89, 9.12), BPoint(322.73, 14.33), BPoint(346.69, 31.67) },
39 { BPoint(330.49, 37.85), BPoint(314.36, 44.25), BPoint(299.55, 54.17) },
40 { BPoint(292.48, 52.54), BPoint(289.31, 49.70), BPoint(285.62, 47.03) },
41 { BPoint(283.73, 54.61), BPoint(284.46, 57.94), BPoint(285.62, 60.60) },
42 { BPoint(259.78, 76.14), BPoint(233.24, 90.54), BPoint(202.41, 98.10) },
43 { BPoint(194.43, 95.36), BPoint(185.96, 92.39), BPoint(179.63, 88.33) },
44 { BPoint(180.15, 94.75), BPoint(182.73, 99.76), BPoint(185.62, 104.53) },
45 { BPoint(154.83, 119.46), BPoint(133.21, 118.97), BPoint(125.62, 94.88) },
46 { BPoint(124.70, 98.79), BPoint(124.11, 103.67), BPoint(124.19, 110.60) },
47 { BPoint(116.42, 111.81), BPoint(85.82, 99.60), BPoint(83.25, 51.96) },
48 { BPoint(62.50, 42.57), BPoint(58.12, 33.18), BPoint(50.98, 23.81) } };
49 static const int kLeafCurveCount
= sizeof(kLeafCurves
) / sizeof(kLeafCurves
[0]);
50 static const float kLeafWidth
= 372.f
;
51 static const float kLeafHeight
= 121.f
;
54 static const rgb_color kColors
[][2] = {
55 { {255, 114, 0, 255}, {255, 159, 0, 255} },
56 { {50, 160, 40, 255}, {125, 210, 32, 255} },
57 { {250, 190, 30, 255}, {255, 214, 125, 255} } };
58 static const int kColorCount
= sizeof(kColors
) / sizeof(kColors
[0]);
60 // bounds for settings
61 static const int kMinimumDropRate
= 2, kMaximumDropRate
= 50;
62 static const int kMinimumLeafSize
= 50, kMaximumLeafSize
= 1000;
63 static const int kMaximumSizeVariation
= 200;
67 MSG_SET_DROP_RATE
= 'drop',
68 MSG_SET_LEAF_SIZE
= 'size',
69 MSG_SET_SIZE_VARIATION
= 'svry',
73 extern "C" BScreenSaver
*
74 instantiate_screen_saver(BMessage
* msg
, image_id image
)
76 return new Leaves(msg
, image
);
80 Leaves::Leaves(BMessage
* archive
, image_id id
)
82 BScreenSaver(archive
, id
),
88 if (archive
->FindInt32("Leaves drop rate", &fDropRate
) != B_OK
)
90 if (archive
->FindInt32("Leaves size", &fLeafSize
) != B_OK
)
92 if (archive
->FindInt32("Leaves variation", &fSizeVariation
) != B_OK
)
99 Leaves::StartConfig(BView
* view
)
101 BRect bounds
= view
->Bounds();
102 bounds
.InsetBy(10, 10);
103 BRect
frame(0, 0, bounds
.Width(), 20);
105 BSlider
* dropRateSlider
= new BSlider(frame
, "drop rate",
106 B_TRANSLATE("Drop rate:"), new BMessage(MSG_SET_DROP_RATE
),
107 kMinimumDropRate
, kMaximumDropRate
, B_BLOCK_THUMB
,
108 B_FOLLOW_LEFT_RIGHT
| B_FOLLOW_BOTTOM
);
109 dropRateSlider
->SetValue(fDropRate
);
110 dropRateSlider
->ResizeToPreferred();
111 bounds
.bottom
-= dropRateSlider
->Bounds().Height() * 1.5;
112 dropRateSlider
->MoveTo(bounds
.LeftBottom());
113 view
->AddChild(dropRateSlider
);
115 BSlider
* leafSizeSlider
= new BSlider(frame
, "leaf size",
116 B_TRANSLATE("Leaf size:"), new BMessage(MSG_SET_LEAF_SIZE
),
117 kMinimumLeafSize
, kMaximumLeafSize
, B_BLOCK_THUMB
,
118 B_FOLLOW_LEFT_RIGHT
| B_FOLLOW_BOTTOM
);
119 leafSizeSlider
->SetValue(fLeafSize
);
120 leafSizeSlider
->ResizeToPreferred();
121 bounds
.bottom
-= leafSizeSlider
->Bounds().Height() * 1.5;
122 leafSizeSlider
->MoveTo(bounds
.LeftBottom());
123 view
->AddChild(leafSizeSlider
);
125 BSlider
* sizeVariationSlider
= new BSlider(frame
, "variation",
126 B_TRANSLATE("Size variation:"), new BMessage(MSG_SET_SIZE_VARIATION
),
127 0, kMaximumSizeVariation
, B_BLOCK_THUMB
,
128 B_FOLLOW_LEFT_RIGHT
| B_FOLLOW_BOTTOM
);
129 sizeVariationSlider
->SetValue(fSizeVariation
);
130 sizeVariationSlider
->ResizeToPreferred();
131 bounds
.bottom
-= sizeVariationSlider
->Bounds().Height() * 1.5;
132 sizeVariationSlider
->MoveTo(bounds
.LeftBottom());
133 view
->AddChild(sizeVariationSlider
);
135 BTextView
* textView
= new BTextView(bounds
, B_EMPTY_STRING
,
136 bounds
.OffsetToCopy(0., 0.), B_FOLLOW_ALL
, B_WILL_DRAW
);
137 textView
->SetViewColor(view
->ViewColor());
138 BString name
= B_TRANSLATE("Leaves");
141 text
<< B_TRANSLATE("by Deyan Genovski, Geoffry Song");
144 textView
->Insert(text
.String());
145 textView
->SetStylable(true);
146 textView
->SetFontAndColor(0, name
.Length(), be_bold_font
);
147 textView
->MakeEditable(false);
148 view
->AddChild(textView
);
150 BWindow
* window
= view
->Window();
151 if (window
) window
->AddHandler(this);
153 dropRateSlider
->SetTarget(this);
154 leafSizeSlider
->SetTarget(this);
155 sizeVariationSlider
->SetTarget(this);
160 Leaves::StartSaver(BView
* view
, bool preview
)
162 SetTickSize(10000000 / fDropRate
);
165 view
->SetLineMode(B_ROUND_CAP
, B_ROUND_JOIN
);
172 Leaves::SaveState(BMessage
* into
) const
175 if ((status
= into
->AddInt32("Leaves drop rate", fDropRate
)) != B_OK
)
177 if ((status
= into
->AddInt32("Leaves size", fLeafSize
)) != B_OK
)
179 if ((status
= into
->AddInt32("Leaves variation", fSizeVariation
)) != B_OK
)
186 Leaves::MessageReceived(BMessage
* message
)
188 switch (message
->what
) {
189 case MSG_SET_DROP_RATE
:
192 if (message
->FindInt32("be:value", &dropRate
) == B_OK
)
193 fDropRate
= dropRate
;
197 case MSG_SET_LEAF_SIZE
:
200 if (message
->FindInt32("be:value", &leafSize
) == B_OK
)
201 fLeafSize
= leafSize
;
205 case MSG_SET_SIZE_VARIATION
:
208 if (message
->FindInt32("be:value", &sizeVariation
) == B_OK
)
209 fSizeVariation
= sizeVariation
;
214 BHandler::MessageReceived(message
);
220 Leaves::Draw(BView
* view
, int32 frame
)
222 float scale
= fLeafSize
/ kLeafWidth
/ (kMaximumLeafSize
* 2);
223 scale
*= view
->Bounds().Width();
224 scale
+= scale
* drand48() * fSizeVariation
/ 100.;
226 BAffineTransform transform
;
227 transform
.TranslateBy(-kLeafWidth
/ 2, -kLeafHeight
/ 2);
228 // draw the leaf centered on the point
229 transform
.RotateBy(drand48() * 2. * M_PI
);
230 if ((rand() & 64) == 0) transform
.ScaleBy(-1., 1.);
231 // flip half of the time
232 transform
.ScaleBy(scale
);
233 transform
.TranslateBy(_RandomPoint(view
->Bounds()));
235 BPoint center
= transform
.Apply(BPoint(kLeafWidth
/ 2, kLeafHeight
/ 2));
236 BPoint gradientOffset
= BPoint(60 * scale
, 80 * scale
);
237 BGradientLinear
gradient(center
- gradientOffset
, center
+ gradientOffset
);
238 int color
= (rand() / 7) % kColorCount
;
239 gradient
.AddColor(kColors
[color
][0], 0.f
);
240 gradient
.AddColor(kColors
[color
][1], 255.f
);
243 leafShape
.MoveTo(transform
.Apply(kLeafBegin
));
244 for (int i
= 0; i
< kLeafCurveCount
; ++i
) {
246 for (int j
= 0; j
< 3; ++j
)
247 control
[j
] = transform
.Apply(kLeafCurves
[i
][j
]);
248 leafShape
.BezierTo(control
);
253 view
->SetDrawingMode(B_OP_ALPHA
);
254 view
->SetHighColor(0, 0, 0, 50);
255 for (int i
= 2; i
>= 0; --i
) {
256 view
->SetOrigin(i
* 0.1, i
* 0.3);
257 view
->SetPenSize(i
* 2);
258 view
->StrokeShape(&leafShape
);
261 view
->FillShape(&leafShape
, gradient
);
266 Leaves::_RandomPoint(const BRect
& bound
)
268 return BPoint(drand48() * (bound
.right
- bound
.left
) + bound
.left
,
269 drand48() * (bound
.bottom
- bound
.top
) + bound
.top
);