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