1/*
2Open Tracker License
3
4Terms and Conditions
5
6Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7
8Permission is hereby granted, free of charge, to any person obtaining a copy of
9this software and associated documentation files (the "Software"), to deal including
10the Software without restriction, including without limitation the rights to
11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12of the Software, and to permit persons to whom the Software is furnished to do
13so, subject to the following conditions:
14
15The above copyright notice and this permission notice applies to all licensees
16and shall be included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25Except as contained in this notice, the name of Be Incorporated shall not be
26used in advertising or otherwise to promote the sale, use or other dealings in
27this Software without prior written authorization from Be Incorporated.
28
29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30of Be Incorporated in the United States and other countries. Other brand product
31names are registered trademarks or trademarks of their respective holders.
32All rights reserved.
33*/
34
35
36#include "DraggableContainerIcon.h"
37
38#include <algorithm>
39
40#include <ControlLook.h>
41#include <IconUtils.h>
42#include <MenuItem.h>
43#include <Region.h>
44
45#include "ContainerWindow.h"
46#include "IconCache.h"
47#include "Model.h"
48
49
50// amount to move the mouse over for before a drag starts
51const float kDragSlop = 3.0f;
52
53
54DraggableContainerIcon::DraggableContainerIcon(BSize iconSize)
55	:
56	BView("DraggableContainerIcon", B_WILL_DRAW),
57	fIconSize(iconSize),
58	fDragButton(0),
59	fDragStarted(false)
60{
61	SetExplicitMinSize(BSize(iconSize.Width() + 5, iconSize.Height()));
62	SetExplicitMaxSize(BSize(iconSize.Width() + 5, B_SIZE_UNSET));
63}
64
65
66void
67DraggableContainerIcon::MouseDown(BPoint where)
68{
69	// we only like container windows
70	BContainerWindow* window = dynamic_cast<BContainerWindow*>(Window());
71	ThrowOnAssert(window != NULL);
72
73	// we don't like the Trash icon (because it cannot be moved)
74	if (window->IsTrash() || window->IsPrintersDir())
75		return;
76
77	uint32 buttons;
78	window->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
79
80	if (IconCache::sIconCache->IconHitTest(where, window->TargetModel(),
81			kNormalIcon, fIconSize)) {
82		// The click hit the icon, initiate a drag
83		fDragButton = buttons
84			& (B_PRIMARY_MOUSE_BUTTON | B_SECONDARY_MOUSE_BUTTON);
85		fDragStarted = false;
86		fClickPoint = where;
87	} else
88		fDragButton = 0;
89
90	if (!fDragButton)
91		Window()->Activate(true);
92}
93
94
95void
96DraggableContainerIcon::MouseUp(BPoint)
97{
98	if (!fDragStarted)
99		Window()->Activate(true);
100
101	fDragButton = 0;
102	fDragStarted = false;
103}
104
105
106void
107DraggableContainerIcon::MouseMoved(BPoint where, uint32, const BMessage*)
108{
109	if (fDragButton == 0 || fDragStarted
110		|| (abs((int32)(where.x - fClickPoint.x)) <= kDragSlop
111			&& abs((int32)(where.y - fClickPoint.y)) <= kDragSlop))
112		return;
113
114	BContainerWindow* window = static_cast<BContainerWindow*>(Window());
115		// we can only get here in a BContainerWindow
116	Model* model = window->TargetModel();
117
118	// Find the required height
119	BFont font;
120	GetFont(&font);
121
122	font_height fontHeight;
123	font.GetHeight(&fontHeight);
124	float height = ceilf(fontHeight.ascent + fontHeight.descent
125		+ fontHeight.leading + 2 + Bounds().Height() + 8);
126
127	BRect rect(0, 0, std::max(Bounds().Width(),
128		font.StringWidth(model->Name()) + 4), height);
129	BBitmap* dragBitmap = new BBitmap(rect, B_RGBA32, true);
130
131	dragBitmap->Lock();
132	BView* view = new BView(dragBitmap->Bounds(), "", B_FOLLOW_NONE, 0);
133	dragBitmap->AddChild(view);
134	view->SetOrigin(0, 0);
135	BRect clipRect(view->Bounds());
136	BRegion newClip;
137	newClip.Set(clipRect);
138	view->ConstrainClippingRegion(&newClip);
139
140	// Transparent draw magic
141	view->SetHighColor(0, 0, 0, 0);
142	view->FillRect(view->Bounds());
143	view->SetDrawingMode(B_OP_ALPHA);
144
145	rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
146	textColor.alpha = 128;
147		// set the level of transparency by value
148	view->SetHighColor(textColor);
149	view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);
150
151	// Draw the icon
152	float hIconOffset = (rect.Width() - Bounds().Width()) / 2;
153	IconCache::sIconCache->Draw(model, view, BPoint(hIconOffset, 0),
154		kNormalIcon, fIconSize, true);
155
156	// See if we need to truncate the string
157	BString nameString = model->Name();
158	if (view->StringWidth(model->Name()) > rect.Width()) {
159		view->TruncateString(&nameString, B_TRUNCATE_MIDDLE,
160			rect.Width() - 5);
161	}
162
163	// Draw the label
164	float leftText = (view->StringWidth(nameString.String())
165		- Bounds().Width()) / 2;
166	view->MovePenTo(BPoint(hIconOffset - leftText + 2, Bounds().Height()
167		+ (fontHeight.ascent + 2)));
168	view->DrawString(nameString.String());
169
170	view->Sync();
171	dragBitmap->Unlock();
172
173	BMessage message(B_SIMPLE_DATA);
174	message.AddRef("refs", model->EntryRef());
175	message.AddPoint("click_pt", fClickPoint);
176
177	BPoint tmpLoc;
178	uint32 button;
179	GetMouse(&tmpLoc, &button);
180	if (button)
181		message.AddInt32("buttons", (int32)button);
182
183	if ((button & B_PRIMARY_MOUSE_BUTTON) != 0) {
184		// add an action specifier to the message, so that it is not copied
185		message.AddInt32("be:actions", (modifiers() & B_OPTION_KEY) != 0
186			? B_COPY_TARGET : B_MOVE_TARGET);
187	}
188
189	fDragStarted = true;
190	fDragButton = 0;
191
192	DragMessage(&message, dragBitmap, B_OP_ALPHA,
193		BPoint(fClickPoint.x + hIconOffset, fClickPoint.y), this);
194}
195
196
197void
198DraggableContainerIcon::Draw(BRect updateRect)
199{
200	BContainerWindow* window = dynamic_cast<BContainerWindow*>(Window());
201	ThrowOnAssert(window != NULL);
202
203	BRect rect(Bounds());
204	rgb_color base = ui_color(B_MENU_BACKGROUND_COLOR);
205	be_control_look->DrawBorder(this, rect, updateRect, base, B_PLAIN_BORDER,
206		0, BControlLook::B_BOTTOM_BORDER);
207	be_control_look->DrawMenuBarBackground(this, rect, updateRect, base, 0,
208		BControlLook::B_ALL_BORDERS & ~BControlLook::B_LEFT_BORDER);
209
210	// Draw the icon, straddling the border
211	SetDrawingMode(B_OP_ALPHA);
212	SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
213	float iconOffsetX = (Bounds().Width() - fIconSize.Width()) / 2;
214	float iconOffsetY = (Bounds().Height() - fIconSize.Height()) / 2;
215	IconCache::sIconCache->Draw(window->TargetModel(), this,
216		BPoint(iconOffsetX, iconOffsetY), kNormalIcon, fIconSize, true);
217}
218
219