157d51b24SRyan Leavengood /*
2*01f623b0SJohn Scipione * Copyright 2010-2013, Haiku, Inc. All Rights Reserved.
357d51b24SRyan Leavengood * Distributed under the terms of the MIT license.
457d51b24SRyan Leavengood *
557d51b24SRyan Leavengood * Authors:
657d51b24SRyan Leavengood * Deyan Genovski, deangenovski@gmail.com
757d51b24SRyan Leavengood * Geoffry Song, goffrie@gmail.com
857d51b24SRyan Leavengood */
9*01f623b0SJohn Scipione
10*01f623b0SJohn Scipione
1157d51b24SRyan Leavengood #include "Leaves.h"
1257d51b24SRyan Leavengood
1357d51b24SRyan Leavengood #include <stdlib.h>
1457d51b24SRyan Leavengood #include <time.h>
1557d51b24SRyan Leavengood
1657d51b24SRyan Leavengood #include <AffineTransform.h>
17a6b6cbbcSPhilippe Houdoin #include <Catalog.h>
1857d51b24SRyan Leavengood #include <GradientLinear.h>
1957d51b24SRyan Leavengood #include <Shape.h>
2057d51b24SRyan Leavengood #include <Slider.h>
2157d51b24SRyan Leavengood #include <TextView.h>
2257d51b24SRyan Leavengood
2357d51b24SRyan Leavengood
24546208a5SOliver Tappe #undef B_TRANSLATION_CONTEXT
25546208a5SOliver Tappe #define B_TRANSLATION_CONTEXT "Leaves"
26a6b6cbbcSPhilippe Houdoin
27a6b6cbbcSPhilippe Houdoin
2857d51b24SRyan Leavengood // path data for the leaf shape
2957d51b24SRyan Leavengood static const BPoint kLeafBegin(56.24793f, 15.46287f);
3057d51b24SRyan Leavengood static BPoint kLeafCurves[][3] = {
3157d51b24SRyan Leavengood { BPoint(61.14, 28.89), BPoint(69.78, 38.25), BPoint(83.48, 44.17) },
3257d51b24SRyan Leavengood { BPoint(99.46, 37.52), BPoint(113.27, 29.61), BPoint(134.91, 30.86) },
3357d51b24SRyan Leavengood { BPoint(130.58, 36.53), BPoint(126.74, 42.44), BPoint(123.84, 48.81) },
3457d51b24SRyan Leavengood { BPoint(131.81, 42.22), BPoint(137.53, 38.33), BPoint(144.37, 33.10) },
3557d51b24SRyan Leavengood { BPoint(169.17, 23.55), BPoint(198.90, 15.55), BPoint(232.05, 10.51) },
3657d51b24SRyan Leavengood { BPoint(225.49, 18.37), BPoint(219.31, 28.17), BPoint(217.41, 40.24) },
3757d51b24SRyan Leavengood { BPoint(227.70, 26.60), BPoint(239.97, 14.63), BPoint(251.43, 8.36) },
3857d51b24SRyan Leavengood { BPoint(288.89, 9.12), BPoint(322.73, 14.33), BPoint(346.69, 31.67) },
3957d51b24SRyan Leavengood { BPoint(330.49, 37.85), BPoint(314.36, 44.25), BPoint(299.55, 54.17) },
4057d51b24SRyan Leavengood { BPoint(292.48, 52.54), BPoint(289.31, 49.70), BPoint(285.62, 47.03) },
4157d51b24SRyan Leavengood { BPoint(283.73, 54.61), BPoint(284.46, 57.94), BPoint(285.62, 60.60) },
4257d51b24SRyan Leavengood { BPoint(259.78, 76.14), BPoint(233.24, 90.54), BPoint(202.41, 98.10) },
4357d51b24SRyan Leavengood { BPoint(194.43, 95.36), BPoint(185.96, 92.39), BPoint(179.63, 88.33) },
4457d51b24SRyan Leavengood { BPoint(180.15, 94.75), BPoint(182.73, 99.76), BPoint(185.62, 104.53) },
4557d51b24SRyan Leavengood { BPoint(154.83, 119.46), BPoint(133.21, 118.97), BPoint(125.62, 94.88) },
4657d51b24SRyan Leavengood { BPoint(124.70, 98.79), BPoint(124.11, 103.67), BPoint(124.19, 110.60) },
4757d51b24SRyan Leavengood { BPoint(116.42, 111.81), BPoint(85.82, 99.60), BPoint(83.25, 51.96) },
4857d51b24SRyan Leavengood { BPoint(62.50, 42.57), BPoint(58.12, 33.18), BPoint(50.98, 23.81) } };
4957d51b24SRyan Leavengood static const int kLeafCurveCount = sizeof(kLeafCurves) / sizeof(kLeafCurves[0]);
5057d51b24SRyan Leavengood static const float kLeafWidth = 372.f;
5157d51b24SRyan Leavengood static const float kLeafHeight = 121.f;
5257d51b24SRyan Leavengood
5357d51b24SRyan Leavengood // leaf colors
5457d51b24SRyan Leavengood static const rgb_color kColors[][2] = {
5557d51b24SRyan Leavengood { {255, 114, 0, 255}, {255, 159, 0, 255} },
5657d51b24SRyan Leavengood { {50, 160, 40, 255}, {125, 210, 32, 255} },
5757d51b24SRyan Leavengood { {250, 190, 30, 255}, {255, 214, 125, 255} } };
5857d51b24SRyan Leavengood static const int kColorCount = sizeof(kColors) / sizeof(kColors[0]);
5957d51b24SRyan Leavengood
6057d51b24SRyan Leavengood // bounds for settings
6157d51b24SRyan Leavengood static const int kMinimumDropRate = 2, kMaximumDropRate = 50;
6257d51b24SRyan Leavengood static const int kMinimumLeafSize = 50, kMaximumLeafSize = 1000;
6357d51b24SRyan Leavengood static const int kMaximumSizeVariation = 200;
6457d51b24SRyan Leavengood
65*01f623b0SJohn Scipione // message constants
6657d51b24SRyan Leavengood enum {
6757d51b24SRyan Leavengood MSG_SET_DROP_RATE = 'drop',
6857d51b24SRyan Leavengood MSG_SET_LEAF_SIZE = 'size',
6957d51b24SRyan Leavengood MSG_SET_SIZE_VARIATION = 'svry',
7057d51b24SRyan Leavengood };
7157d51b24SRyan Leavengood
7257d51b24SRyan Leavengood
7357d51b24SRyan Leavengood extern "C" BScreenSaver*
instantiate_screen_saver(BMessage * msg,image_id image)7457d51b24SRyan Leavengood instantiate_screen_saver(BMessage* msg, image_id image)
7557d51b24SRyan Leavengood {
7657d51b24SRyan Leavengood return new Leaves(msg, image);
7757d51b24SRyan Leavengood }
7857d51b24SRyan Leavengood
7957d51b24SRyan Leavengood
Leaves(BMessage * archive,image_id id)8057d51b24SRyan Leavengood Leaves::Leaves(BMessage* archive, image_id id)
8157d51b24SRyan Leavengood :
8257d51b24SRyan Leavengood BScreenSaver(archive, id),
8357d51b24SRyan Leavengood fDropRate(10),
8457d51b24SRyan Leavengood fLeafSize(150),
8557d51b24SRyan Leavengood fSizeVariation(50)
8657d51b24SRyan Leavengood {
8757d51b24SRyan Leavengood if (archive) {
8857d51b24SRyan Leavengood if (archive->FindInt32("Leaves drop rate", &fDropRate) != B_OK)
8957d51b24SRyan Leavengood fDropRate = 10;
9057d51b24SRyan Leavengood if (archive->FindInt32("Leaves size", &fLeafSize) != B_OK)
9157d51b24SRyan Leavengood fLeafSize = 150;
9257d51b24SRyan Leavengood if (archive->FindInt32("Leaves variation", &fSizeVariation) != B_OK)
9357d51b24SRyan Leavengood fSizeVariation = 50;
9457d51b24SRyan Leavengood }
9557d51b24SRyan Leavengood }
9657d51b24SRyan Leavengood
9757d51b24SRyan Leavengood
9857d51b24SRyan Leavengood void
StartConfig(BView * view)9957d51b24SRyan Leavengood Leaves::StartConfig(BView* view)
10057d51b24SRyan Leavengood {
10157d51b24SRyan Leavengood BRect bounds = view->Bounds();
10257d51b24SRyan Leavengood bounds.InsetBy(10, 10);
10357d51b24SRyan Leavengood BRect frame(0, 0, bounds.Width(), 20);
10457d51b24SRyan Leavengood
105*01f623b0SJohn Scipione BSlider* dropRateSlider = new BSlider(frame, "drop rate",
106a6b6cbbcSPhilippe Houdoin B_TRANSLATE("Drop rate:"), new BMessage(MSG_SET_DROP_RATE),
107a6b6cbbcSPhilippe Houdoin kMinimumDropRate, kMaximumDropRate, B_BLOCK_THUMB,
108a6b6cbbcSPhilippe Houdoin B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM);
109*01f623b0SJohn Scipione dropRateSlider->SetValue(fDropRate);
110*01f623b0SJohn Scipione dropRateSlider->ResizeToPreferred();
111*01f623b0SJohn Scipione bounds.bottom -= dropRateSlider->Bounds().Height() * 1.5;
112*01f623b0SJohn Scipione dropRateSlider->MoveTo(bounds.LeftBottom());
113*01f623b0SJohn Scipione view->AddChild(dropRateSlider);
11457d51b24SRyan Leavengood
115*01f623b0SJohn Scipione BSlider* leafSizeSlider = new BSlider(frame, "leaf size",
116a6b6cbbcSPhilippe Houdoin B_TRANSLATE("Leaf size:"), new BMessage(MSG_SET_LEAF_SIZE),
117a6b6cbbcSPhilippe Houdoin kMinimumLeafSize, kMaximumLeafSize, B_BLOCK_THUMB,
118a6b6cbbcSPhilippe Houdoin B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM);
119*01f623b0SJohn Scipione leafSizeSlider->SetValue(fLeafSize);
120*01f623b0SJohn Scipione leafSizeSlider->ResizeToPreferred();
121*01f623b0SJohn Scipione bounds.bottom -= leafSizeSlider->Bounds().Height() * 1.5;
122*01f623b0SJohn Scipione leafSizeSlider->MoveTo(bounds.LeftBottom());
123*01f623b0SJohn Scipione view->AddChild(leafSizeSlider);
12457d51b24SRyan Leavengood
125*01f623b0SJohn Scipione BSlider* sizeVariationSlider = new BSlider(frame, "variation",
126a6b6cbbcSPhilippe Houdoin B_TRANSLATE("Size variation:"), new BMessage(MSG_SET_SIZE_VARIATION),
127a6b6cbbcSPhilippe Houdoin 0, kMaximumSizeVariation, B_BLOCK_THUMB,
128a6b6cbbcSPhilippe Houdoin B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM);
129*01f623b0SJohn Scipione sizeVariationSlider->SetValue(fSizeVariation);
130*01f623b0SJohn Scipione sizeVariationSlider->ResizeToPreferred();
131*01f623b0SJohn Scipione bounds.bottom -= sizeVariationSlider->Bounds().Height() * 1.5;
132*01f623b0SJohn Scipione sizeVariationSlider->MoveTo(bounds.LeftBottom());
133*01f623b0SJohn Scipione view->AddChild(sizeVariationSlider);
13457d51b24SRyan Leavengood
13557d51b24SRyan Leavengood BTextView* textView = new BTextView(bounds, B_EMPTY_STRING,
13657d51b24SRyan Leavengood bounds.OffsetToCopy(0., 0.), B_FOLLOW_ALL, B_WILL_DRAW);
13757d51b24SRyan Leavengood textView->SetViewColor(view->ViewColor());
138439859b9SPhilippe Houdoin BString name = B_TRANSLATE("Leaves");
139439859b9SPhilippe Houdoin BString text = name;
140439859b9SPhilippe Houdoin text << "\n\n";
141a6b6cbbcSPhilippe Houdoin text << B_TRANSLATE("by Deyan Genovski, Geoffry Song");
142a6b6cbbcSPhilippe Houdoin text << "\n\n";
143439859b9SPhilippe Houdoin
144a6b6cbbcSPhilippe Houdoin textView->Insert(text.String());
14557d51b24SRyan Leavengood textView->SetStylable(true);
146439859b9SPhilippe Houdoin textView->SetFontAndColor(0, name.Length(), be_bold_font);
14757d51b24SRyan Leavengood textView->MakeEditable(false);
14857d51b24SRyan Leavengood view->AddChild(textView);
14957d51b24SRyan Leavengood
15057d51b24SRyan Leavengood BWindow* window = view->Window();
15157d51b24SRyan Leavengood if (window) window->AddHandler(this);
15257d51b24SRyan Leavengood
153*01f623b0SJohn Scipione dropRateSlider->SetTarget(this);
154*01f623b0SJohn Scipione leafSizeSlider->SetTarget(this);
155*01f623b0SJohn Scipione sizeVariationSlider->SetTarget(this);
15657d51b24SRyan Leavengood }
15757d51b24SRyan Leavengood
15857d51b24SRyan Leavengood
15957d51b24SRyan Leavengood status_t
StartSaver(BView * view,bool preview)16057d51b24SRyan Leavengood Leaves::StartSaver(BView* view, bool preview)
16157d51b24SRyan Leavengood {
16257d51b24SRyan Leavengood SetTickSize(10000000 / fDropRate);
16357d51b24SRyan Leavengood srand48(time(NULL));
16457d51b24SRyan Leavengood
16557d51b24SRyan Leavengood view->SetLineMode(B_ROUND_CAP, B_ROUND_JOIN);
16657d51b24SRyan Leavengood
16757d51b24SRyan Leavengood return B_OK;
16857d51b24SRyan Leavengood }
16957d51b24SRyan Leavengood
17057d51b24SRyan Leavengood
17157d51b24SRyan Leavengood status_t
SaveState(BMessage * into) const17257d51b24SRyan Leavengood Leaves::SaveState(BMessage* into) const
17357d51b24SRyan Leavengood {
17457d51b24SRyan Leavengood status_t status;
17557d51b24SRyan Leavengood if ((status = into->AddInt32("Leaves drop rate", fDropRate)) != B_OK)
17657d51b24SRyan Leavengood return status;
17757d51b24SRyan Leavengood if ((status = into->AddInt32("Leaves size", fLeafSize)) != B_OK)
17857d51b24SRyan Leavengood return status;
17957d51b24SRyan Leavengood if ((status = into->AddInt32("Leaves variation", fSizeVariation)) != B_OK)
18057d51b24SRyan Leavengood return status;
18157d51b24SRyan Leavengood return B_OK;
18257d51b24SRyan Leavengood }
18357d51b24SRyan Leavengood
18457d51b24SRyan Leavengood
18557d51b24SRyan Leavengood void
MessageReceived(BMessage * message)18657d51b24SRyan Leavengood Leaves::MessageReceived(BMessage* message)
18757d51b24SRyan Leavengood {
18857d51b24SRyan Leavengood switch (message->what) {
18957d51b24SRyan Leavengood case MSG_SET_DROP_RATE:
190*01f623b0SJohn Scipione {
191*01f623b0SJohn Scipione int32 dropRate;
192*01f623b0SJohn Scipione if (message->FindInt32("be:value", &dropRate) == B_OK)
193*01f623b0SJohn Scipione fDropRate = dropRate;
19457d51b24SRyan Leavengood break;
195*01f623b0SJohn Scipione }
196*01f623b0SJohn Scipione
19757d51b24SRyan Leavengood case MSG_SET_LEAF_SIZE:
198*01f623b0SJohn Scipione {
199*01f623b0SJohn Scipione int32 leafSize;
200*01f623b0SJohn Scipione if (message->FindInt32("be:value", &leafSize) == B_OK)
201*01f623b0SJohn Scipione fLeafSize = leafSize;
20257d51b24SRyan Leavengood break;
203*01f623b0SJohn Scipione }
204*01f623b0SJohn Scipione
20557d51b24SRyan Leavengood case MSG_SET_SIZE_VARIATION:
206*01f623b0SJohn Scipione {
207*01f623b0SJohn Scipione int32 sizeVariation;
208*01f623b0SJohn Scipione if (message->FindInt32("be:value", &sizeVariation) == B_OK)
209*01f623b0SJohn Scipione fSizeVariation = sizeVariation;
21057d51b24SRyan Leavengood break;
211*01f623b0SJohn Scipione }
212*01f623b0SJohn Scipione
21357d51b24SRyan Leavengood default:
21457d51b24SRyan Leavengood BHandler::MessageReceived(message);
21557d51b24SRyan Leavengood }
21657d51b24SRyan Leavengood }
21757d51b24SRyan Leavengood
21857d51b24SRyan Leavengood
21957d51b24SRyan Leavengood void
Draw(BView * view,int32 frame)22057d51b24SRyan Leavengood Leaves::Draw(BView* view, int32 frame)
22157d51b24SRyan Leavengood {
22257d51b24SRyan Leavengood float scale = fLeafSize / kLeafWidth / (kMaximumLeafSize * 2);
22357d51b24SRyan Leavengood scale *= view->Bounds().Width();
22457d51b24SRyan Leavengood scale += scale * drand48() * fSizeVariation / 100.;
22557d51b24SRyan Leavengood
22657d51b24SRyan Leavengood BAffineTransform transform;
22757d51b24SRyan Leavengood transform.TranslateBy(-kLeafWidth / 2, -kLeafHeight / 2);
22857d51b24SRyan Leavengood // draw the leaf centered on the point
22957d51b24SRyan Leavengood transform.RotateBy(drand48() * 2. * M_PI);
23057d51b24SRyan Leavengood if ((rand() & 64) == 0) transform.ScaleBy(-1., 1.);
23157d51b24SRyan Leavengood // flip half of the time
23257d51b24SRyan Leavengood transform.ScaleBy(scale);
23357d51b24SRyan Leavengood transform.TranslateBy(_RandomPoint(view->Bounds()));
23457d51b24SRyan Leavengood
23557d51b24SRyan Leavengood BPoint center = transform.Apply(BPoint(kLeafWidth / 2, kLeafHeight / 2));
23657d51b24SRyan Leavengood BPoint gradientOffset = BPoint(60 * scale, 80 * scale);
23757d51b24SRyan Leavengood BGradientLinear gradient(center - gradientOffset, center + gradientOffset);
23857d51b24SRyan Leavengood int color = (rand() / 7) % kColorCount;
23957d51b24SRyan Leavengood gradient.AddColor(kColors[color][0], 0.f);
24057d51b24SRyan Leavengood gradient.AddColor(kColors[color][1], 255.f);
24157d51b24SRyan Leavengood
24257d51b24SRyan Leavengood BShape leafShape;
24357d51b24SRyan Leavengood leafShape.MoveTo(transform.Apply(kLeafBegin));
24457d51b24SRyan Leavengood for (int i = 0; i < kLeafCurveCount; ++i) {
24557d51b24SRyan Leavengood BPoint control[3];
24657d51b24SRyan Leavengood for (int j = 0; j < 3; ++j)
24757d51b24SRyan Leavengood control[j] = transform.Apply(kLeafCurves[i][j]);
24857d51b24SRyan Leavengood leafShape.BezierTo(control);
24957d51b24SRyan Leavengood }
25057d51b24SRyan Leavengood leafShape.Close();
25157d51b24SRyan Leavengood
25257d51b24SRyan Leavengood view->PushState();
25357d51b24SRyan Leavengood view->SetDrawingMode(B_OP_ALPHA);
25457d51b24SRyan Leavengood view->SetHighColor(0, 0, 0, 50);
25557d51b24SRyan Leavengood for (int i = 2; i >= 0; --i) {
25657d51b24SRyan Leavengood view->SetOrigin(i * 0.1, i * 0.3);
25757d51b24SRyan Leavengood view->SetPenSize(i * 2);
25857d51b24SRyan Leavengood view->StrokeShape(&leafShape);
25957d51b24SRyan Leavengood }
26057d51b24SRyan Leavengood view->PopState();
26157d51b24SRyan Leavengood view->FillShape(&leafShape, gradient);
26257d51b24SRyan Leavengood }
26357d51b24SRyan Leavengood
26457d51b24SRyan Leavengood
26557d51b24SRyan Leavengood inline BPoint
_RandomPoint(const BRect & bound)26657d51b24SRyan Leavengood Leaves::_RandomPoint(const BRect& bound)
26757d51b24SRyan Leavengood {
26857d51b24SRyan Leavengood return BPoint(drand48() * (bound.right - bound.left) + bound.left,
26957d51b24SRyan Leavengood drand48() * (bound.bottom - bound.top) + bound.top);
27057d51b24SRyan Leavengood }
271