xref: /haiku/src/apps/clock/cl_view.cpp (revision fc7456e9b1ec38c941134ed6d01c438cf289381e)
1 /*
2  * Copyright 1999, Be Incorporated. All Rights Reserved.
3  * This file may be used under the terms of the Be Sample Code License.
4  *
5  */
6 
7 #include "clock.h"
8 #include "cl_view.h"
9 
10 
11 #include <Alert.h>
12 #include <Bitmap.h>
13 #include <Catalog.h>
14 #include <Debug.h>
15 #include <Dragger.h>
16 #include <Entry.h>
17 #include <Resources.h>
18 #include <Roster.h>
19 
20 
21 #include <time.h>
22 #include <math.h>
23 
24 
25 #undef B_TRANSLATION_CONTEXT
26 #define B_TRANSLATION_CONTEXT "Clock"
27 
28 
29 TOffscreenView::TOffscreenView(BRect frame, const char *name, short mRadius,
30 		short hRadius, short offset, long face, bool show)
31 	: BView(frame, name, B_FOLLOW_NONE, B_WILL_DRAW),
32 	  fHours(0),
33 	  fMinutes(0),
34 	  fSeconds(0),
35 	  fOffset(offset),
36 	  fHoursRadius(hRadius),
37 	  fMinutesRadius(mRadius),
38 	  fFace(face),
39 	  fShowSeconds(show),
40 	  fInner(NULL),
41 	  fCenter(NULL)
42 {
43 	for (short i = 0; i <= 8; i++)
44 		fClockFace[i] = NULL;
45 
46 	status_t error;
47 	BResources rsrcs;
48 	error = rsrcs.SetToImage(&&dummy_label);
49 dummy_label:
50 	if (error == B_OK) {
51 		size_t len;
52 		void *picH;
53 		BRect theRect(0, 0, 82, 82);
54 		for (short loop = 0; loop <= 8; loop++) {
55 			if ((picH = rsrcs.FindResource('PICT', loop + 4, &len))) {
56 				fClockFace[loop] = new BBitmap(theRect, B_CMAP8);
57 				fClockFace[loop]->SetBits(picH, len, 0, B_CMAP8);
58 				free(picH);
59 			}
60 		}
61 
62 		theRect.Set(0,0,15,15);
63 		if ((picH = rsrcs.FindResource(B_MINI_ICON_TYPE, "center", &len))) {
64 			fCenter = new BBitmap(theRect, B_CMAP8);
65 			fCenter->SetBits(picH, len, 0, B_CMAP8);
66 			free(picH);
67 		}
68 
69 		theRect.Set(0,0,2,2);
70 		if ((picH = rsrcs.FindResource('PICT', 13, &len))) {
71 			fInner = new BBitmap(theRect, B_CMAP8);
72 			fInner->SetBits(picH, len, 0, B_CMAP8);
73 			free(picH);
74 		}
75 	}
76 
77 	float x, y;
78 	float counter;
79 	short index = 0;
80 
81 	// Generate minutes points array
82 	for (counter = 90; counter >= 0; counter -= 6, index++) {
83 		x = mRadius * cos(((360 - counter)/180.0) * M_PI);
84 		x += 41;
85 		y = mRadius * sin(((360 - counter)/180.0) * M_PI);
86 		y += 41;
87 		fMinutePoints[index].Set(x,y);
88 		x = hRadius * cos(((360 - counter)/180.0) * M_PI);
89 		x += 41;
90 		y = hRadius * sin(((360 - counter)/180.0) * M_PI);
91 		y += 41;
92 		fHourPoints[index].Set(x,y);
93 	}
94 
95 	for (counter = 354; counter > 90; counter -= 6,index++) {
96 		x = mRadius * cos(((360 - counter)/180.0) * M_PI);
97 		x += 41;
98 		y = mRadius * sin(((360 - counter)/180.0) * M_PI);
99 		y += 41;
100 		fMinutePoints[index].Set(x,y);
101 		x = hRadius * cos(((360 - counter)/180.0) * M_PI);
102 		x += 41;
103 		y = hRadius * sin(((360 - counter)/180.0) * M_PI);
104 		y += 41;
105 		fHourPoints[index].Set(x,y);
106 	}
107 }
108 
109 
110 void
111 TOffscreenView::NextFace()
112 {
113 	fFace++;
114 	if (fFace > 8)
115 		fFace = 1;
116 };
117 
118 
119 void
120 TOffscreenView::DrawX()
121 {
122 	ASSERT(Window());
123 
124 	if (Window()->Lock()) {
125 		if (fClockFace[fFace] != NULL)
126 			DrawBitmap(fClockFace[fFace], BPoint(0, 0));
127 
128 		//
129 		// Draw hands
130 		//
131 		SetHighColor(0, 0, 0);
132 		int32 hours = fHours;
133 		if (hours >= 12)
134 			hours -= 12;
135 		hours *= 5;
136 		hours += (fMinutes / 12);
137 		SetDrawingMode(B_OP_OVER);
138 		StrokeLine(BPoint(fOffset, fOffset), fHourPoints[hours]);
139 
140 		if (fCenter != NULL)
141 			DrawBitmap(fCenter, BPoint(fOffset - 3, fOffset - 3));
142 		StrokeLine(BPoint(fOffset, fOffset), fMinutePoints[fMinutes]);
143 		SetHighColor(180, 180, 180);
144 		if (fShowSeconds)
145 			StrokeLine(BPoint(fOffset, fOffset), fMinutePoints[fSeconds]);
146 		SetDrawingMode(B_OP_COPY);
147 		if (fInner != NULL)
148 			DrawBitmap(fInner, BPoint(fOffset - 1, fOffset - 1));
149 		Sync();
150 		Window()->Unlock();
151 	}
152 }
153 
154 
155 TOffscreenView::~TOffscreenView()
156 {
157 	for (int32 counter = 0; counter <= 8; counter++)
158 		delete fClockFace[counter];
159 };
160 
161 
162 //	#pragma mark -
163 
164 
165 TOnscreenView::TOnscreenView(BRect rect, const char *title, short mRadius,
166 		short hRadius, short offset)
167 	: BView(rect, title, B_FOLLOW_NONE,
168 		B_WILL_DRAW | B_PULSE_NEEDED | B_DRAW_ON_CHILDREN),
169 	  fOffscreen(NULL),
170 	  fOffscreenView(NULL)
171 {
172 	InitObject(rect, mRadius, hRadius, offset, 1, TRUE);
173 
174 	rect.OffsetTo(B_ORIGIN);
175 	rect.top = rect.bottom - 7;
176 	rect.left = rect.right - 7;
177 	BDragger *dw = new BDragger(rect, this);
178 	AddChild(dw);
179 }
180 
181 
182 void
183 TOnscreenView::InitObject(BRect rect, short mRadius, short hRadius,
184 	short offset, long face, bool show)
185 {
186 	fOffscreenView = new TOffscreenView(rect, "freqd", mRadius, hRadius, offset, face, show);
187 	fOffscreen = new BBitmap(rect, B_CMAP8, true);
188 	if (fOffscreen != NULL && fOffscreen->Lock()) {
189 		fOffscreen->AddChild(fOffscreenView);
190 		fOffscreen->Unlock();
191 	}
192 
193 	Pulse();
194 }
195 
196 
197 TOnscreenView::~TOnscreenView()
198 {
199 	delete fOffscreen;
200 }
201 
202 
203 TOnscreenView::TOnscreenView(BMessage *data)
204 	: BView(data),
205 	  fOffscreen(NULL),
206 	  fOffscreenView(NULL)
207 {
208 	InitObject(data->FindRect("bounds"), data->FindInt32("mRadius"),
209 		data->FindInt32("hRadius"), data->FindInt32("offset"),
210 		data->FindInt32("face"), data->FindBool("seconds"));
211 }
212 
213 
214 status_t
215 TOnscreenView::Archive(BMessage *data, bool deep) const
216 {
217 	status_t status = BView::Archive(data, deep);
218 	if (status == B_OK)
219 		status = data->AddString("add_on", kAppSignature);
220 
221 	if (status == B_OK)
222 		status = data->AddRect("bounds", Bounds());
223 
224 	if (status == B_OK)
225 		status = data->AddInt32("mRadius", fOffscreenView->fMinutesRadius);
226 
227 	if (status == B_OK)
228 		status = data->AddInt32("hRadius", fOffscreenView->fHoursRadius);
229 
230 	if (status == B_OK)
231 		status = data->AddInt32("offset", fOffscreenView->fOffset);
232 
233 	if (status == B_OK)
234 		status = data->AddBool("seconds", fOffscreenView->fShowSeconds);
235 
236 	if (status == B_OK)
237 		status = data->AddInt32("face", fOffscreenView->fFace);
238 
239 	return status;
240 }
241 
242 
243 BArchivable *
244 TOnscreenView::Instantiate(BMessage *data)
245 {
246 	if (!validate_instantiation(data, "TOnscreenView"))
247 		return NULL;
248 	return new TOnscreenView(data);
249 }
250 
251 
252 void
253 TOnscreenView::Pulse()
254 {
255 	ASSERT(fOffscreen);
256 	ASSERT(fOffscreenView);
257 
258 	time_t current = time(0);
259 	struct tm *loctime = localtime(&current);
260 
261 	short hours = loctime->tm_hour;
262 	short minutes = loctime->tm_min;
263 	short seconds = loctime->tm_sec;
264 
265 	if ((fOffscreenView->fShowSeconds && (seconds != fOffscreenView->fSeconds))
266 		|| (minutes != fOffscreenView->fMinutes)) {
267 			fOffscreenView->fHours = hours;
268 			fOffscreenView->fMinutes = minutes;
269 			fOffscreenView->fSeconds = seconds;
270 			BRect b = Bounds();
271 			b.InsetBy(12,12);
272 			Draw(b);
273 	}
274 }
275 
276 
277 void
278 TOnscreenView::UseFace(short face)
279 {
280 	fOffscreenView->fFace = face;
281 	BRect b = Bounds();
282 	b.InsetBy(12,12);
283 	Draw(b);
284 }
285 
286 
287 void
288 TOnscreenView::ShowSecs(bool secs)
289 {
290 	fOffscreenView->fShowSeconds = secs;
291 	BRect b = Bounds();
292 	b.InsetBy(12,12);
293 	Invalidate(b);
294 }
295 
296 
297 short
298 TOnscreenView::ReturnFace()
299 {
300 	return fOffscreenView->fFace;
301 }
302 
303 
304 short
305 TOnscreenView::ReturnSeconds()
306 {
307 	return fOffscreenView->fShowSeconds;
308 }
309 
310 
311 void
312 TOnscreenView::Draw(BRect rect)
313 {
314 	ASSERT(fOffscreen);
315 	ASSERT(fOffscreenView);
316 
317 	if (fOffscreen->Lock()) {
318 		// Composite the clock offscreen...
319 		fOffscreenView->DrawX();
320 		DrawBitmap(fOffscreen, rect, rect);
321 		fOffscreen->Unlock();
322 	}
323 };
324 
325 
326 void
327 TOnscreenView::MouseDown( BPoint point )
328 {
329 	BPoint	cursor;
330 	uint32	buttons;
331 	BRect	bounds = Bounds();
332 
333 	GetMouse(&cursor,&buttons);
334 	if (buttons & B_SECONDARY_MOUSE_BUTTON) {
335 		fOffscreenView->fShowSeconds = !fOffscreenView->fShowSeconds;
336 		bounds.InsetBy(12,12);
337 		Invalidate(bounds);
338 	} else {
339 		fOffscreenView->NextFace();
340 		Invalidate(bounds);
341 		BView *child = ChildAt(0);
342 		if (child)
343 			child->Invalidate();
344 	}
345 };
346 
347 
348 void
349 TOnscreenView::MessageReceived(BMessage *msg)
350 {
351 	switch(msg->what) {
352 		case B_ABOUT_REQUESTED:
353 		{
354 			BAlert *alert = new BAlert(B_TRANSLATE("About Clock"), B_TRANSLATE(
355 				"Clock (The Replicant version)\n\nCopyright 2002-2020 "
356 				"Haiku, Inc.\n\nOriginally coded by the folks "
357 				"at Be.\n  Copyright 1991-1998, Be Inc."), B_TRANSLATE("OK"));
358 			alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
359 			alert->Go();
360 		}	break;
361 
362 		default:
363 			BView::MessageReceived(msg);
364 	}
365 }
366 
367