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