1/*
2 * Copyright 2011, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "PanelWindow.h"
8
9#include <stdio.h>
10
11#include <GroupLayout.h>
12#include <MessageRunner.h>
13#include <Screen.h>
14
15#include "ApplicationsView.h"
16#include "GroupListView.h"
17#include "Switcher.h"
18#include "WindowsView.h"
19
20
21static const uint32 kMsgShow = 'SHOW';
22static const uint32 kMsgHide = 'HIDE';
23
24static const int32 kMinShowState = 0;
25static const int32 kMaxShowState = 4;
26static const bigtime_t kMoveDelay = 15000;
27	// 25 ms
28
29
30PanelWindow::PanelWindow(uint32 location, uint32 which, team_id team)
31	:
32	BWindow(BRect(-16000, -16000, -15900, -15900), "panel",
33		B_BORDERED_WINDOW_LOOK, B_FLOATING_ALL_WINDOW_FEEL,
34		B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS | B_AVOID_FOCUS,
35		B_ALL_WORKSPACES),
36	fLocation(location),
37	fShowState(kMinShowState)
38{
39	SetLayout(new BGroupLayout(B_HORIZONTAL));
40
41	BView* child = _ViewFor(location, which, team);
42	if (child != NULL)
43		AddChild(child);
44
45	Run();
46	PostMessage(kMsgShow);
47}
48
49
50PanelWindow::~PanelWindow()
51{
52	BMessage message(kMsgLocationFree);
53	message.AddInt32("location", fLocation);
54	be_app->PostMessage(&message);
55}
56
57
58void
59PanelWindow::MessageReceived(BMessage* message)
60{
61	switch (message->what) {
62		case kMsgShow:
63		case kMsgHide:
64			_UpdateShowState(message->what);
65			break;
66
67		default:
68			BWindow::MessageReceived(message);
69			break;
70	}
71}
72
73
74BView*
75PanelWindow::_ViewFor(uint32 location, uint32 which, team_id team) const
76{
77	switch (which) {
78		case kShowApplications:
79			return new ApplicationsView(location);
80		case kShowApplicationWindows:
81			return new WindowsView(team, location);
82
83		default:
84			return NULL;
85	}
86}
87
88
89void
90PanelWindow::_UpdateShowState(uint32 how)
91{
92	if ((how == kMsgShow && fShowState >= kMaxShowState)
93		|| (how == kMsgHide && fShowState <= kMinShowState))
94		return;
95
96	fShowState += how == kMsgShow ? 1 : -1;
97
98	// Compute start and end position depending on the location
99	// TODO: multi-screen support
100	BScreen screen;
101	BRect screenFrame = screen.Frame();
102	BPoint from;
103	BPoint to;
104
105	switch (fLocation) {
106		case kLeftEdge:
107		case kRightEdge:
108			from.y = screenFrame.top
109				+ (screenFrame.Height() - Bounds().Height()) / 2.f;
110			to.y = from.y;
111			break;
112		case kTopEdge:
113		case kBottomEdge:
114			from.x = screenFrame.left
115				+ (screenFrame.Width() - Bounds().Width()) / 2.f;
116			to.x = from.x;
117			break;
118	}
119
120	switch (fLocation) {
121		case kLeftEdge:
122			from.x = screenFrame.left - Bounds().Width();
123			to.x = screenFrame.left;
124			break;
125		case kRightEdge:
126			from.x = screenFrame.right;
127			to.x = screenFrame.right - Bounds().Width();
128			break;
129		case kTopEdge:
130			from.y = screenFrame.top - Bounds().Height();
131			to.y = screenFrame.top;
132			break;
133		case kBottomEdge:
134			from.y = screenFrame.bottom;
135			to.y = screenFrame.bottom - Bounds().Height();
136			break;
137	}
138
139	MoveTo(from.x + _Factor() * (to.x - from.x),
140		from.y + _Factor() * (to.y - from.y));
141
142	if (kMsgShow && IsHidden())
143		Show();
144	else if (fShowState == 0 && kMsgHide && !IsHidden())
145		Quit();
146
147	if ((how == kMsgShow && fShowState < kMaxShowState)
148		|| (how == kMsgHide && fShowState > kMinShowState)) {
149		BMessage move(how);
150		BMessageRunner::StartSending(this, &move, kMoveDelay, 1);
151	} else if (how == kMsgShow) {
152		// Hide the window once the mouse left its frame
153		BMessage hide(kMsgHideWhenMouseMovedOut);
154		hide.AddMessenger("target", this);
155		hide.AddInt32("what", kMsgHide);
156
157		// The window might not span over the whole screen, but one dimension
158		// should be ignored for the cursor movements
159		BRect frame = Frame();
160		switch (fLocation) {
161			case kLeftEdge:
162			case kRightEdge:
163				frame.top = screenFrame.top;
164				frame.bottom = screenFrame.bottom;
165				break;
166			case kTopEdge:
167			case kBottomEdge:
168				frame.left = screenFrame.left;
169				frame.right = screenFrame.right;
170				break;
171		}
172		hide.AddRect("frame", frame);
173		be_app->PostMessage(&hide);
174	}
175}
176
177
178float
179PanelWindow::_Factor()
180{
181	float factor = 1.f * fShowState / kMaxShowState;
182	return 1 - (factor - 1) * (factor - 1);
183}
184