1/*
2 * Copyright (c) 1999-2003 Matthijs Hollemans
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23#include <Alert.h>
24#include <Deskbar.h>
25#include <MenuItem.h>
26#include <PopUpMenu.h>
27#include <String.h>
28#include <stdio.h>
29
30#include "WatchApp.h"
31#include "WatchView.h"
32
33#undef B_TRANSLATION_CONTEXT
34#define B_TRANSLATION_CONTEXT "WatchView"
35
36
37const rgb_color COLOR_FOREGROUND = { 0, 0, 0 };
38
39///////////////////////////////////////////////////////////////////////////////
40
41WatchView::WatchView()
42	:
43	BView(BRect(0, 0, 1, 1), 0, 0, 0)
44{
45}
46
47///////////////////////////////////////////////////////////////////////////////
48
49WatchView::WatchView(BMessage* message)
50	: BView(
51		BRect(0, 0, 15, 15), DESKBAR_ITEM_NAME, B_FOLLOW_NONE,
52		B_WILL_DRAW | B_PULSE_NEEDED)
53{
54	oldTime = 0;
55
56	//SetFont(be_bold_font);
57	SetFont(be_plain_font);
58
59	// Calculate the maximum width for our replicant. Note that the Deskbar
60	// accepts replicants that are wider than 16 pixels, but not replicants
61	// that are higher than 16 pixels.
62
63	float width = StringWidth("@999") + 4;
64	ResizeTo(width, 15);
65
66	SetViewColor(B_TRANSPARENT_COLOR);
67}
68
69///////////////////////////////////////////////////////////////////////////////
70
71WatchView* WatchView::Instantiate(BMessage* archive)
72{
73	if (validate_instantiation(archive, REPLICANT_CLASS))
74	{
75		return new WatchView(archive);
76	}
77
78	return NULL;
79}
80
81///////////////////////////////////////////////////////////////////////////////
82
83status_t WatchView::Archive(BMessage* archive, bool deep) const
84{
85	super::Archive(archive, deep);
86
87	archive->AddString("add_on", APP_SIGNATURE);
88	archive->AddString("class", REPLICANT_CLASS);
89
90	return B_OK;
91}
92
93///////////////////////////////////////////////////////////////////////////////
94
95void WatchView::Draw(BRect updateRect)
96{
97	super::Draw(updateRect);
98
99	char string[5];
100	sprintf(string, "@%03ld", GetInternetTime());
101
102	font_height height;         // center the text horizontally
103	GetFontHeight(&height);     // and vertically in the Deskbar
104	BRect rect = Bounds();
105	float width = StringWidth(string);
106	float x = 1 + (rect.Width() - width)/2;
107	float y = height.ascent
108			    + (rect.Height() - (height.ascent + height.descent))/2;
109
110	SetHighColor(Parent()->ViewColor());
111	FillRect(updateRect);
112
113	SetLowColor(Parent()->ViewColor());
114	SetHighColor(COLOR_FOREGROUND);
115	SetDrawingMode(B_OP_OVER);
116	DrawString(string, BPoint(x, y));
117}
118
119///////////////////////////////////////////////////////////////////////////////
120
121void WatchView::MouseDown(BPoint point)
122{
123	BPopUpMenu* menu = new BPopUpMenu("WatchView", false, false);
124
125	menu->AddItem(new BMenuItem(
126		B_TRANSLATE("About"),
127		new BMessage(B_ABOUT_REQUESTED)));
128
129	menu->AddItem(new BMenuItem(
130		B_TRANSLATE("Quit"), new BMessage(B_QUIT_REQUESTED)));
131
132	menu->SetTargetForItems(this);
133
134	ConvertToScreen(&point);
135	menu->Go(point, true, false, true);
136
137	delete menu;
138}
139
140///////////////////////////////////////////////////////////////////////////////
141
142void WatchView::MessageReceived(BMessage* msg)
143{
144	switch (msg->what)
145	{
146		case B_ABOUT_REQUESTED: OnAboutRequested();          break;
147		case B_QUIT_REQUESTED:  OnQuitRequested();           break;
148		default:                super::MessageReceived(msg); break;
149	}
150}
151
152///////////////////////////////////////////////////////////////////////////////
153
154void WatchView::OnAboutRequested()
155{
156	BString text = B_TRANSLATE("WebWatch %1"
157		"\nAn internet time clock for your Deskbar\n\n"
158		"Created by Matthijs Hollemans\n"
159		"mahlzeit@users.sourceforge.net\n\n"
160		"Thanks to Jason Parks for his help.\n");
161	text.ReplaceFirst("%1", VERSION);
162	BAlert* alert = new BAlert(NULL, text.String(), B_TRANSLATE("OK"));
163	alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
164	alert->Go(NULL);
165}
166
167///////////////////////////////////////////////////////////////////////////////
168
169void WatchView::OnQuitRequested()
170{
171	// According to the Be Book, we are not allowed to do this
172	// since we're a view that's sitting on the Deskbar's shelf.
173	// But it works just fine for me, and I see no other way to
174	// make a Deskbar replicant quit itself.
175
176	BDeskbar deskbar;
177	deskbar.RemoveItem(DESKBAR_ITEM_NAME);
178}
179
180///////////////////////////////////////////////////////////////////////////////
181
182void WatchView::Pulse()
183{
184	int32 currentTime = GetInternetTime();
185	if (oldTime != currentTime)
186	{
187		oldTime = currentTime;
188		Invalidate();
189	}
190}
191
192///////////////////////////////////////////////////////////////////////////////
193
194int32 WatchView::GetInternetTime()
195{
196	// First we get the current time as the number of seconds since
197	// 1 January 1970 GMT and add an hour's worth of seconds to adjust
198	// for the Biel Mean Time (BMT). Then we get the number of seconds
199	// that have passed today, and divide it with the length of a beat
200	// to get the number of elapsed beats.
201
202	return (int32) (((real_time_clock() + 3600) % 86400) / 86.4);
203}
204
205///////////////////////////////////////////////////////////////////////////////
206