2 * Copyright 2007-2014, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
17 #include <ObjectList.h>
20 #include <ScreenSaver.h>
22 #include <StringList.h>
26 #include <BuildScreenSaverDefaultSettingsView.h>
28 #undef B_TRANSLATION_CONTEXT
29 #define B_TRANSLATION_CONTEXT "Screensaver Message"
32 // Double brackets to satisfy a compiler warning
33 const pattern kCheckered
= { { 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0x33, 0x33 } };
35 // Get a clever message from fortune
36 BString
*get_message()
38 BString
*result
= new BString();
39 FILE *file
= popen("/bin/fortune", "r");
44 bytesRead
= fread(buf
, 1, 512, file
);
45 result
->Append(buf
, bytesRead
);
51 if (result
->Length() <= 0) {
52 result
->Append(B_TRANSLATE("Insert clever anecdote or phrase here!"));
60 get_lines(BString
*message
, BStringList
& list
, int *longestLine
)
62 BString
copy(*message
);
63 // Convert tabs to 4 spaces
64 copy
.ReplaceAll("\t", " ");
65 if (copy
.Split("\n", false, list
)) {
67 int32 count
= list
.CountStrings();
68 for (int32 i
= 0; i
< count
; i
++) {
69 int32 length
= list
.StringAt(i
).Length();
70 if (length
> maxLength
) {
81 // Inspired by the classic BeOS screensaver, of course.
82 // Thanks to Jon Watte for writing the original.
83 class Message
: public BScreenSaver
86 Message(BMessage
*archive
, image_id
);
88 void Draw(BView
*view
, int32 frame
);
89 void StartConfig(BView
*view
);
90 status_t
StartSaver(BView
*view
, bool preview
);
93 BObjectList
<font_family
> fFontFamilies
;
99 BScreenSaver
*instantiate_screen_saver(BMessage
*msg
, image_id image
)
101 return new Message(msg
, image
);
105 Message::Message(BMessage
*archive
, image_id id
)
106 : BScreenSaver(archive
, id
)
113 for (int32 i
= 0; i
< fFontFamilies
.CountItems(); i
++) {
114 if (fFontFamilies
.ItemAt(i
))
115 delete fFontFamilies
.ItemAt(i
);
121 Message::StartConfig(BView
*view
)
123 BPrivate::BuildScreenSaverDefaultSettingsView(view
, "Message",
124 B_TRANSLATE("by Ryan Leavengood"));
129 Message::StartSaver(BView
*view
, bool preview
)
132 // Scale factor is based on the system I developed this on, in
133 // other words other factors below depend on this.
134 fScaleFactor
= view
->Bounds().Height() / 1024;
137 int numFamilies
= count_font_families();
138 for (int32 i
= 0; i
< numFamilies
; i
++) {
139 font_family
* family
= new font_family
[1];
141 if (get_font_family(i
, family
, &flags
) == B_OK
142 && (flags
& B_IS_FIXED
) == 0) {
143 // Do not add fixed fonts
144 fFontFamilies
.AddItem(family
);
149 // Seed the random number generator
150 srand((int)system_time());
152 // Set tick size to 30,000,000 microseconds = 30 seconds
153 SetTickSize(30000000);
160 Message::Draw(BView
*view
, int32 frame
)
162 if (view
== NULL
|| view
->Window() == NULL
|| !view
->Window()->IsLocked())
165 BScreen
screen(view
->Window());
166 if (!screen
.IsValid())
169 // Double-buffered drawing
170 BBitmap
buffer(view
->Bounds(), screen
.ColorSpace(), true);
171 if (buffer
.InitCheck() != B_OK
)
174 BView
offscreen(view
->Bounds(), NULL
, 0, 0);
175 buffer
.AddChild(&offscreen
);
179 rgb_color base_color
= {(uint8
)(rand() % 25), (uint8
)(rand() % 25),
180 (uint8
)(rand() % 25)};
181 offscreen
.SetHighColor(base_color
);
182 offscreen
.SetLowColor(tint_color(base_color
, 0.815F
));
183 offscreen
.FillRect(offscreen
.Bounds(), kCheckered
);
184 rgb_color colors
[8] = {
185 tint_color(base_color
, B_LIGHTEN_1_TINT
),
186 tint_color(base_color
, 0.795F
),
187 tint_color(base_color
, 0.851F
),
188 tint_color(base_color
, 0.926F
),
189 tint_color(base_color
, 1.05F
),
190 tint_color(base_color
, B_DARKEN_1_TINT
),
191 tint_color(base_color
, B_DARKEN_2_TINT
),
192 tint_color(base_color
, B_DARKEN_3_TINT
),
195 offscreen
.SetDrawingMode(B_OP_OVER
);
197 // Set the basic font parameters, including random font family
199 offscreen
.GetFont(&font
);
200 font
.SetFace(B_BOLD_FACE
);
201 font
.SetFamilyAndStyle(*(fFontFamilies
.ItemAt(rand() % fFontFamilies
.CountItems())), NULL
);
202 offscreen
.SetFont(&font
);
205 BString
*message
= get_message();
206 BString
*origMessage
= new BString();
207 message
->CopyInto(*origMessage
, 0, message
->Length());
208 // Replace newlines and tabs with spaces
209 message
->ReplaceSet("\n\t", ' ');
211 int height
= (int) offscreen
.Bounds().Height();
212 int width
= (int) offscreen
.Bounds().Width();
214 // From 14 to 22 iterations
215 int32 iterations
= (rand() % 8) + 14;
216 for (int32 i
= 0; i
< iterations
; i
++) {
217 // Randomly set font size and shear
219 offscreen
.GetFont(&font
);
220 float fontSize
= ((rand() % 320) + 42) * fScaleFactor
;
221 font
.SetSize(fontSize
);
222 // Set the shear off 90 about 1/2 of the time
224 font
.SetShear((float) ((rand() % 135) + (rand() % 45)));
227 offscreen
.SetFont(&font
);
229 // Randomly set drawing location
230 int x
= (rand() % width
) - (rand() % width
/((rand() % 8)+1));
231 int y
= rand() % height
;
234 offscreen
.SetHighColor(colors
[rand() % 8]);
235 int strLength
= message
->Length();
236 // See how wide this string is with the current font
237 float strWidth
= offscreen
.StringWidth(message
->String());
238 int drawingLength
= (int) (strLength
* (width
/ strWidth
));
240 if (drawingLength
>= strLength
)
241 drawingLength
= strLength
;
243 start
= rand() % (strLength
- drawingLength
);
244 char *toDraw
= new char[drawingLength
+1];
245 strncpy(toDraw
, message
->String()+start
, drawingLength
);
246 toDraw
[drawingLength
] = 0;
247 offscreen
.DrawString(toDraw
, BPoint(x
, y
));
251 // Now draw the full message in a nice translucent box, but only
252 // if this isn't preview mode
254 BFont
font(be_fixed_font
);
256 offscreen
.SetFont(&font
);
257 font_height fontHeight
;
258 font
.GetHeight(&fontHeight
);
259 float lineHeight
= fontHeight
.ascent
+ fontHeight
.descent
260 + fontHeight
.leading
;
264 int32 count
= get_lines(origMessage
, lines
, &longestLine
);
266 float stringWidth
= font
.StringWidth(lines
.StringAt(longestLine
).String());
267 BRect
box(0, 0, stringWidth
+ 20, (lineHeight
* count
) + 20);
268 box
.OffsetTo((width
- box
.Width()) / 2, height
- box
.Height() - 40);
270 offscreen
.SetDrawingMode(B_OP_ALPHA
);
271 base_color
.alpha
= 128;
272 offscreen
.SetHighColor(base_color
);
273 offscreen
.FillRoundRect(box
, 8, 8);
274 offscreen
.SetHighColor(205, 205, 205);
275 BPoint start
= box
.LeftTop();
277 start
.y
+= 10 + fontHeight
.ascent
+ fontHeight
.leading
;
278 for (int i
= 0; i
< count
; i
++) {
279 offscreen
.DrawString(lines
.StringAt(i
).String(), start
);
280 start
.y
+= lineHeight
;
289 view
->DrawBitmap(&buffer
);
290 buffer
.RemoveChild(&offscreen
);