xref: /haiku/src/add-ons/screen_savers/message/Message.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
1 /*
2  * Copyright 2007, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Ryan Leavengood
7  */
8 
9 
10 #include <Bitmap.h>
11 #include <Font.h>
12 #include <List.h>
13 #include <Picture.h>
14 #include <Screen.h>
15 #include <ScreenSaver.h>
16 #include <String.h>
17 #include <StringView.h>
18 #include <View.h>
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 
24 
25 // Double brackets to satisfy a compiler warning
26 const pattern kCheckered = { { 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0x33, 0x33 } };
27 
28 
29 // Get a clever message from fortune
30 BString *get_message()
31 {
32 	BString *result = new BString();
33 	system("fortune > /tmp/fortune_msg");
34 	FILE *file = fopen("/tmp/fortune_msg", "r");
35 	if (file) {
36 		char buf[512];
37 		int bytesRead;
38 		while (!feof(file)) {
39 			bytesRead = fread(buf, 1, 512, file);
40 			result->Append(buf, bytesRead);
41 		}
42 		fclose(file);
43 	}
44 	remove("/tmp/fortune_msg");
45 
46 	// Just in case
47 	if (result->Length() <= 0) {
48 		result->Append("Insert clever anecdote or phrase here!");
49 	}
50 
51 	return result;
52 }
53 
54 
55 // Inspired by the classic BeOS screensaver, of course.
56 // Thanks to Jon Watte for writing the original.
57 class Message : public BScreenSaver
58 {
59 	public:
60 					Message(BMessage *archive, image_id);
61 					~Message();
62 		void		Draw(BView *view, int32 frame);
63 		void		StartConfig(BView *view);
64 		status_t	StartSaver(BView *view, bool preview);
65 
66 	private:
67 		BList			*fFontFamilies;
68 		float			fScaleFactor;
69 };
70 
71 
72 BScreenSaver *instantiate_screen_saver(BMessage *msg, image_id image)
73 {
74 	return new Message(msg, image);
75 }
76 
77 
78 Message::Message(BMessage *archive, image_id id)
79  :	BScreenSaver(archive, id)
80 {
81 }
82 
83 
84 Message::~Message()
85 {
86 	if (fFontFamilies) {
87 		for (int32 i = 0; i < fFontFamilies->CountItems(); i++) {
88 			if (fFontFamilies->ItemAt(i))
89 				delete ((font_family) fFontFamilies->ItemAt(i));
90 		}
91 		delete fFontFamilies;
92 	}
93 }
94 
95 
96 void
97 Message::StartConfig(BView *view)
98 {
99 	view->AddChild(new BStringView(BRect(20, 10, 200, 35), "", "Message, by Ryan Leavengood"));
100 	view->AddChild(new BStringView(BRect(20, 40, 200, 65), "", "Inspired by Jon Watte's Original"));
101 }
102 
103 
104 status_t
105 Message::StartSaver(BView *view, bool preview)
106 {
107 	// Scale factor is based on the system I developed this on, in
108 	// other words other factors below depend on this.
109 	fScaleFactor = view->Bounds().Height() / 1024;
110 
111 	// Get font families
112 	int numFamilies = count_font_families();
113 	fFontFamilies = new BList();
114 	for (int32 i = 0; i < numFamilies; i++) {
115 		font_family *family = new font_family[1];
116 		uint32 flags;
117 		if (get_font_family(i, family, &flags) == B_OK) {
118 			// Do not add fixed fonts
119 			if (!(flags & B_IS_FIXED))
120 				fFontFamilies->AddItem(*family);
121 		}
122 	}
123 
124 	// Seed the random number generator
125 	srand((int)system_time());
126 
127 	// Set tick size to 30,000,000 microseconds = 30 seconds
128 	SetTickSize(30000000);
129 
130 	return B_OK;
131 }
132 
133 
134 void
135 Message::Draw(BView *view, int32 frame)
136 {
137 	// Double-buffered drawing
138 	BScreen screen;
139 	BBitmap buffer(view->Bounds(), screen.ColorSpace(), true);
140 	BView offscreen(view->Bounds(), NULL, 0, 0);
141 	buffer.AddChild(&offscreen);
142 	buffer.Lock();
143 
144 	// Set up the colors
145 	rgb_color base_color = {rand() % 25, rand() % 25, rand() % 25};
146 	offscreen.SetHighColor(base_color);
147 	offscreen.SetLowColor(tint_color(base_color, 0.815F));
148 	offscreen.FillRect(offscreen.Bounds(), kCheckered);
149 	rgb_color colors[8] = {
150 		tint_color(base_color, B_LIGHTEN_1_TINT),
151 		tint_color(base_color, 0.795F),
152 		tint_color(base_color, 0.851F),
153 		tint_color(base_color, 0.926F),
154 		tint_color(base_color, 1.05F),
155 		tint_color(base_color, B_DARKEN_1_TINT),
156 		tint_color(base_color, B_DARKEN_2_TINT),
157 		tint_color(base_color, B_DARKEN_3_TINT),
158 	};
159 
160 	// Set the basic font parameters, including random font family
161 	BFont font;
162 	offscreen.GetFont(&font);
163 	font.SetFlags(B_DISABLE_ANTIALIASING);
164 	font.SetFace(B_BOLD_FACE);
165 	font.SetFamilyAndStyle((font_family) fFontFamilies->ItemAt(rand() % fFontFamilies->CountItems()), NULL);
166 	offscreen.SetFont(&font);
167 
168 	// Get the message
169 	// TODO: Display the whole message at the bottom of the screen
170 	// in a translucent rect
171 	BString *message = get_message();
172 	// Replace newlines and tabs with spaces
173 	message->ReplaceSet("\n\t", ' ');
174 
175 	int height = (int) offscreen.Bounds().Height();
176 	int width = (int) offscreen.Bounds().Width();
177 
178 	// From 8 to 16 iterations
179 	int32 iterations = (rand() % 9) + 8;
180 	for (int32 i = 0; i < iterations; i++) {
181 		// Randomly set font size and shear
182 		BFont font;
183 		offscreen.GetFont(&font);
184 		float fontSize = ((rand() % 320) + 42) * fScaleFactor;
185 		font.SetSize(fontSize);
186 		// Set the shear off 90 about 1/2 of the time
187 		if (rand() % 2 == 1)
188 			font.SetShear((float) ((rand() % 135) + (rand() % 45)));
189 		else
190 			font.SetShear(90.0);
191 		offscreen.SetFont(&font);
192 
193 		// Randomly set drawing location
194 		// TODO: Improve this
195 		int x = (rand() % width) - (rand() % width/((rand() % 8)+1));
196 		int y = (rand() % height) - (rand() % height/((rand() % 8)+1));
197 
198 		// Draw new text
199 		offscreen.SetHighColor(colors[rand() % 8]);
200 		int strLength = message->Length();
201 		// See how wide this string is with the current font
202 		float strWidth = offscreen.StringWidth(message->String());
203 		int drawingLength = (int) (strLength * (width / strWidth));
204 		int start = 0;
205 		if (drawingLength >= strLength)
206 			drawingLength = strLength;
207 		else
208 			start = rand() % (strLength - drawingLength);
209 		char *toDraw = new char[drawingLength+1];
210 		strncpy(toDraw, message->String()+start, drawingLength);
211 		toDraw[drawingLength] = 0;
212 		offscreen.DrawString(toDraw, BPoint(x, y));
213 		delete toDraw;
214 	}
215 
216 	offscreen.Sync();
217 	buffer.Unlock();
218 	view->DrawBitmap(&buffer);
219 	buffer.RemoveChild(&offscreen);
220 }
221 
222