xref: /haiku/src/preferences/time/AnalogClock.cpp (revision 3cb015b1ee509d69c643506e8ff573808c86dcfc)
1 /*
2  * Copyright 2004-2006, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Mike Berg (inseculous)
7  */
8 
9 /*! Notes: OffscreenClock borrows heavily from the clock source. */
10 
11 
12 #include "AnalogClock.h"
13 #include "Bitmaps.h"
14 #include "TimeMessages.h"
15 
16 #include <Alert.h>
17 #include <Bitmap.h>
18 #include <Debug.h>
19 #include <Dragger.h>
20 #include <Window.h>
21 
22 
23 class OffscreenClock : public BView {
24 	public:
25 		OffscreenClock(BRect frame, const char *name);
26 		virtual ~OffscreenClock();
27 
28 		void DrawClock();
29 		BPoint Position();
30 
31 		void SetTo(int32 hour, int32 minute, int32 second);
32 
33 	private:
34 		BBitmap *fBitmap;
35 		BBitmap *fCenterBitmap;
36 		BBitmap *fCapBitmap;
37 		BPoint fCenter;
38 
39 		BPoint fMinutePoints[60];
40 		BPoint fHourPoints[60];
41 		short fHours;
42 		short fMinutes;
43 		short fSeconds;
44 };
45 
46 const BRect kClockRect(0, 0, kClockFaceWidth -1, kClockFaceHeight -1);
47 const BRect kCenterRect(0, 0, kCenterWidth -1, kCenterHeight -1);
48 const BRect kCapRect(0, 0, kCapWidth -1, kCapHeight -1);
49 
50 /*!
51 	Analog Clock face rendering view.
52 */
53 OffscreenClock::OffscreenClock(BRect frame, const char *name)
54 	: BView(frame, name, B_NOT_RESIZABLE, B_WILL_DRAW)
55 {
56 	fBitmap = new BBitmap(kClockRect, kClockFaceColorSpace);
57 	fBitmap->SetBits(kClockFaceBits, (kClockFaceWidth) *(kClockFaceHeight +3), 0, kClockFaceColorSpace);
58 
59 	ReplaceTransparentColor(fBitmap, ui_color(B_PANEL_BACKGROUND_COLOR));
60 
61 	fCenterBitmap = new BBitmap(kCenterRect, kCenterColorSpace);
62 	fCenterBitmap->SetBits(kCenterBits, (kCenterWidth) *(kCenterHeight +1), 0, kCenterColorSpace);
63 
64 	fCapBitmap = new BBitmap(kCapRect, kCapColorSpace);
65 	fCapBitmap->SetBits(kCapBits, (kCapWidth +1) *(kCapHeight +1) +1, 0, kCapColorSpace);
66 
67 	fCenter = BPoint(42, 42);
68 
69 	float counter;
70 	short index;
71 	float x, y, mRadius, hRadius;
72 
73 	mRadius = fCenter.x - 12;
74 	hRadius = mRadius - 10;
75 	index = 0;
76 
77 	//
78 	// Generate minutes/hours points array
79 	//
80 	for (counter = 90; counter >= 0; counter -= 6,index++) {
81 		x = mRadius * cos(((360 - counter)/180.0) * 3.1415);
82 		x += fCenter.x;
83 		y = mRadius * sin(((360 - counter)/180.0) * 3.1415);
84 		y += fCenter.x;
85 		fMinutePoints[index].Set(x,y);
86 		x = hRadius * cos(((360 - counter)/180.0) * 3.1415);
87 		x += fCenter.x;
88 		y = hRadius * sin(((360 - counter)/180.0) * 3.1415);
89 		y += fCenter.x;
90 		fHourPoints[index].Set(x,y);
91 	}
92 
93 	for (counter = 354; counter > 90; counter -= 6,index++) {
94 		x = mRadius * cos(((360 - counter)/180.0) * 3.1415);
95 		x += fCenter.x;
96 		y = mRadius * sin(((360 - counter)/180.0) * 3.1415);
97 		y += fCenter.x;
98 		fMinutePoints[index].Set(x,y);
99 		x = hRadius * cos(((360 - counter)/180.0) * 3.1415);
100 		x += fCenter.x;
101 		y = hRadius * sin(((360 - counter)/180.0) * 3.1415);
102 		y += fCenter.x;
103 		fHourPoints[index].Set(x,y);
104 	}
105 }
106 
107 
108 OffscreenClock::~OffscreenClock()
109 {
110 	delete fBitmap;
111 	delete fCenterBitmap;
112 	delete fCapBitmap;
113 }
114 
115 
116 void
117 OffscreenClock::SetTo(int32 hour, int32 minute, int32 second)
118 {
119 	if (fSeconds != second || fMinutes != minute || fHours != hour) {
120 		fHours = hour;
121 		fMinutes = minute;
122 		fSeconds = second;
123 	}
124 }
125 
126 
127 void
128 OffscreenClock::DrawClock()
129 {
130 	ASSERT(Window()->IsLocked());
131 
132 	// draw clockface
133 	SetDrawingMode(B_OP_COPY);
134 	DrawBitmap(fBitmap, BPoint(0, 0));
135 
136 	SetHighColor(0, 0, 0, 255);
137 
138 	short hours = fHours;
139 	if (hours >= 12)
140 		hours -= 12;
141 
142 	hours *= 5;
143 	hours += (fMinutes / 12);
144 
145 	// draw center hub
146 	SetDrawingMode(B_OP_OVER);
147 	DrawBitmap(fCenterBitmap, fCenter - BPoint(kCenterWidth/2.0, kCenterHeight/2.0));
148 
149 	// draw hands
150 	StrokeLine(fCenter, fHourPoints[hours]);
151 	StrokeLine(fCenter, fMinutePoints[fMinutes]);
152 	SetHighColor(tint_color(HighColor(), B_LIGHTEN_1_TINT));
153 	StrokeLine(fCenter, fMinutePoints[fSeconds]);
154 
155 	// draw center cap
156 	DrawBitmap(fCapBitmap, fCenter -BPoint(kCapWidth/2.0, kCapHeight/2.0));
157 
158 	Sync();
159 }
160 
161 
162 //	#pragma mark -
163 
164 
165 /*!
166 	BView to display clock face of current time.
167 */
168 TAnalogClock::TAnalogClock(BRect frame, const char *name, uint32 resizingmode, uint32 flags)
169 	: BView(frame, name, resizingmode, flags | B_DRAW_ON_CHILDREN)
170 {
171 	_InitView(frame);
172 }
173 
174 
175 TAnalogClock::~TAnalogClock()
176 {
177 	delete fBitmap;
178 }
179 
180 
181 void
182 TAnalogClock::_InitView(BRect rect)
183 {
184 	fClock = new OffscreenClock(kClockRect, "offscreen");
185 	fBitmap = new BBitmap(kClockRect, B_CMAP8, true);
186 	fBitmap->Lock();
187 	fBitmap->AddChild(fClock);
188 	fBitmap->Unlock();
189 }
190 
191 
192 void
193 TAnalogClock::AttachedToWindow()
194 {
195 	SetViewColor(B_TRANSPARENT_COLOR);
196 }
197 
198 
199 void
200 TAnalogClock::MessageReceived(BMessage *message)
201 {
202 	int32 change;
203 	switch (message->what) {
204 		case B_OBSERVER_NOTICE_CHANGE:
205 			message->FindInt32(B_OBSERVE_WHAT_CHANGE, &change);
206 			switch (change) {
207 				case H_TM_CHANGED:
208 				{
209 					int32 hour = 0;
210 					int32 minute = 0;
211 					int32 second = 0;
212 					if (message->FindInt32("hour", &hour) == B_OK
213 					 && message->FindInt32("minute", &minute) == B_OK
214 					 && message->FindInt32("second", &second) == B_OK)
215 						SetTo(hour, minute, second);
216 					break;
217 				}
218 				default:
219 					BView::MessageReceived(message);
220 					break;
221 			}
222 		break;
223 		default:
224 			BView::MessageReceived(message);
225 			break;
226 	}
227 }
228 
229 
230 void
231 TAnalogClock::Draw(BRect /*updateRect*/)
232 {
233 	SetHighColor(0, 100, 10);
234 
235 	if (fBitmap->Lock()) {
236 		fClock->DrawClock();
237 		DrawBitmap(fBitmap, BPoint(0, 0));
238 		fBitmap->Unlock();
239 	}
240 }
241 
242 
243 void
244 TAnalogClock::SetTo(int32 hour, int32 minute, int32 second)
245 {
246 	fClock->SetTo(hour, minute, second);
247 	Invalidate();
248 }
249