btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / apps / launchbox / PadView.cpp
blob012392388c2d3b6c8514e3427d770cad57f531ae
1 /*
2 * Copyright 2006-2009, Stephan Aßmus <superstippi@gmx.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
6 #include "PadView.h"
8 #include <stdio.h>
10 #include <Application.h>
11 #include <Catalog.h>
12 #include <GroupLayout.h>
13 #include <MenuItem.h>
14 #include <Message.h>
15 #include <PopUpMenu.h>
16 #include <Region.h>
17 #include <Screen.h>
18 #include <SpaceLayoutItem.h>
20 #include "LaunchButton.h"
21 #include "MainWindow.h"
24 #undef B_TRANSLATION_CONTEXT
25 #define B_TRANSLATION_CONTEXT "LaunchBox"
28 static bigtime_t sActivationDelay = 40000;
29 static const uint32 kIconSizes[] = { 16, 20, 24, 32, 40, 48, 64 };
32 enum {
33 MSG_TOGGLE_LAYOUT = 'tgll',
34 MSG_SET_ICON_SIZE = 'stis',
35 MSG_SET_IGNORE_DOUBLECLICK = 'strd'
39 PadView::PadView(const char* name)
40 : BView(name, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE, NULL),
41 fDragging(false),
42 fClickTime(0),
43 fButtonLayout(new BGroupLayout(B_VERTICAL, 4)),
44 fIconSize(DEFAULT_ICON_SIZE)
46 SetViewColor(B_TRANSPARENT_32_BIT);
47 SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
48 get_click_speed(&sActivationDelay);
50 fButtonLayout->SetInsets(2, 7, 2, 2);
51 SetLayout(fButtonLayout);
55 PadView::~PadView()
60 void
61 PadView::Draw(BRect updateRect)
63 rgb_color background = LowColor();
64 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
65 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
66 BRect r(Bounds());
67 BeginLineArray(4);
68 AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), light);
69 AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), light);
70 AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), shadow);
71 AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), shadow);
72 EndLineArray();
73 r.InsetBy(1.0, 1.0);
74 StrokeRect(r, B_SOLID_LOW);
75 r.InsetBy(1.0, 1.0);
76 // dots along top
77 BPoint dot = r.LeftTop();
78 int32 current;
79 int32 stop;
80 BPoint offset;
81 BPoint next;
82 if (Orientation() == B_VERTICAL) {
83 current = (int32)dot.x;
84 stop = (int32)r.right;
85 offset = BPoint(0, 1);
86 next = BPoint(1, -4);
87 r.top += 5.0;
88 } else {
89 current = (int32)dot.y;
90 stop = (int32)r.bottom;
91 offset = BPoint(1, 0);
92 next = BPoint(-4, 1);
93 r.left += 5.0;
95 int32 num = 1;
96 while (current <= stop) {
97 rgb_color col1;
98 rgb_color col2;
99 if (num == 1) {
100 col1 = shadow;
101 col2 = background;
102 } else if (num == 2) {
103 col1 = background;
104 col2 = light;
105 } else {
106 col1 = background;
107 col2 = background;
108 num = 0;
110 SetHighColor(col1);
111 StrokeLine(dot, dot, B_SOLID_HIGH);
112 SetHighColor(col2);
113 dot += offset;
114 StrokeLine(dot, dot, B_SOLID_HIGH);
115 dot += offset;
116 StrokeLine(dot, dot, B_SOLID_LOW);
117 dot += offset;
118 SetHighColor(col1);
119 StrokeLine(dot, dot, B_SOLID_HIGH);
120 dot += offset;
121 SetHighColor(col2);
122 StrokeLine(dot, dot, B_SOLID_HIGH);
123 // next pixel
124 num++;
125 dot += next;
126 current++;
128 FillRect(r, B_SOLID_LOW);
132 void
133 PadView::MessageReceived(BMessage* message)
135 switch (message->what) {
136 case MSG_TOGGLE_LAYOUT:
137 if (fButtonLayout->Orientation() == B_HORIZONTAL) {
138 fButtonLayout->SetInsets(2, 7, 2, 2);
139 fButtonLayout->SetOrientation(B_VERTICAL);
140 } else {
141 fButtonLayout->SetInsets(7, 2, 2, 2);
142 fButtonLayout->SetOrientation(B_HORIZONTAL);
144 break;
146 case MSG_SET_ICON_SIZE:
147 uint32 size;
148 if (message->FindInt32("size", (int32*)&size) == B_OK)
149 SetIconSize(size);
150 break;
152 case MSG_SET_IGNORE_DOUBLECLICK:
153 SetIgnoreDoubleClick(!IgnoreDoubleClick());
154 break;
156 default:
157 BView::MessageReceived(message);
158 break;
163 void
164 PadView::MouseDown(BPoint where)
166 BWindow* window = Window();
167 if (window == NULL)
168 return;
170 BRegion region;
171 GetClippingRegion(&region);
172 if (!region.Contains(where))
173 return;
175 bool handle = true;
176 for (int32 i = 0; BView* child = ChildAt(i); i++) {
177 if (child->Frame().Contains(where)) {
178 handle = false;
179 break;
182 if (!handle)
183 return;
185 BMessage* message = window->CurrentMessage();
186 if (message == NULL)
187 return;
189 uint32 buttons;
190 message->FindInt32("buttons", (int32*)&buttons);
191 if (buttons & B_SECONDARY_MOUSE_BUTTON) {
192 BRect r = Bounds();
193 r.InsetBy(2.0, 2.0);
194 r.top += 6.0;
195 if (r.Contains(where)) {
196 DisplayMenu(where);
197 } else {
198 // sends the window to the back
199 window->Activate(false);
201 } else {
202 if (system_time() - fClickTime < sActivationDelay) {
203 window->Minimize(true);
204 fClickTime = 0;
205 } else {
206 window->Activate();
207 fDragOffset = ConvertToScreen(where) - window->Frame().LeftTop();
208 fDragging = true;
209 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
210 fClickTime = system_time();
216 void
217 PadView::MouseUp(BPoint where)
219 if (BWindow* window = Window()) {
220 uint32 buttons;
221 window->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
222 if (buttons & B_PRIMARY_MOUSE_BUTTON
223 && system_time() - fClickTime < sActivationDelay
224 && window->IsActive())
225 window->Activate();
227 fDragging = false;
231 void
232 PadView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
234 MainWindow* window = dynamic_cast<MainWindow*>(Window());
235 if (window == NULL)
236 return;
238 if (fDragging) {
239 window->MoveTo(ConvertToScreen(where) - fDragOffset);
240 } else if (window->AutoRaise()) {
241 where = ConvertToScreen(where);
242 BScreen screen(window);
243 BRect frame = screen.Frame();
244 BRect windowFrame = window->Frame();
245 if (where.x == frame.left || where.x == frame.right
246 || where.y == frame.top || where.y == frame.bottom) {
247 BPoint position = window->ScreenPosition();
248 bool raise = false;
249 if (fabs(0.5 - position.x) > fabs(0.5 - position.y)) {
250 // left or right border
251 if (where.y >= windowFrame.top
252 && where.y <= windowFrame.bottom) {
253 if (position.x < 0.5 && where.x == frame.left)
254 raise = true;
255 else if (position.x > 0.5 && where.x == frame.right)
256 raise = true;
258 } else {
259 // top or bottom border
260 if (where.x >= windowFrame.left && where.x <= windowFrame.right) {
261 if (position.y < 0.5 && where.y == frame.top)
262 raise = true;
263 else if (position.y > 0.5 && where.y == frame.bottom)
264 raise = true;
267 if (raise)
268 window->Activate();
274 void
275 PadView::AddButton(LaunchButton* button, LaunchButton* beforeButton)
277 button->SetIconSize(fIconSize);
279 if (beforeButton)
280 fButtonLayout->AddView(fButtonLayout->IndexOfView(beforeButton), button);
281 else
282 fButtonLayout->AddView(button);
284 _NotifySettingsChanged();
288 bool
289 PadView::RemoveButton(LaunchButton* button)
291 bool result = fButtonLayout->RemoveView(button);
292 if (result)
293 _NotifySettingsChanged();
294 return result;
298 LaunchButton*
299 PadView::ButtonAt(int32 index) const
301 BLayoutItem* item = fButtonLayout->ItemAt(index);
302 if (item == NULL)
303 return NULL;
304 return dynamic_cast<LaunchButton*>(item->View());
308 void
309 PadView::DisplayMenu(BPoint where, LaunchButton* button) const
311 MainWindow* window = dynamic_cast<MainWindow*>(Window());
312 if (window == NULL)
313 return;
315 LaunchButton* nearestButton = button;
316 if (!nearestButton) {
317 // find the nearest button
318 for (int32 i = 0; (nearestButton = ButtonAt(i)); i++) {
319 if (nearestButton->Frame().top > where.y)
320 break;
323 BPopUpMenu* menu = new BPopUpMenu(B_TRANSLATE("launch popup"), false, false);
324 // add button
325 BMessage* message = new BMessage(MSG_ADD_SLOT);
326 message->AddPointer("be:source", (void*)nearestButton);
327 BMenuItem* item = new BMenuItem(B_TRANSLATE("Add button here"), message);
328 item->SetTarget(window);
329 menu->AddItem(item);
330 // button options
331 if (button) {
332 // clear button
333 message = new BMessage(MSG_CLEAR_SLOT);
334 message->AddPointer("be:source", (void*)button);
335 item = new BMenuItem(B_TRANSLATE("Clear button"), message);
336 item->SetTarget(window);
337 menu->AddItem(item);
338 // remove button
339 message = new BMessage(MSG_REMOVE_SLOT);
340 message->AddPointer("be:source", (void*)button);
341 item = new BMenuItem(B_TRANSLATE("Remove button"), message);
342 item->SetTarget(window);
343 menu->AddItem(item);
344 // Open containing folder button
345 if (button->Ref() != NULL) {
346 message = new BMessage(MSG_OPEN_CONTAINING_FOLDER);
347 message->AddPointer("be:source", (void*)button);
348 item = new BMenuItem(B_TRANSLATE("Open containing folder"), message);
349 item->SetTarget(window);
350 menu->AddItem(item);
352 // set button description
353 if (button->Ref()) {
354 message = new BMessage(MSG_SET_DESCRIPTION);
355 message->AddPointer("be:source", (void*)button);
356 item = new BMenuItem(B_TRANSLATE("Set description" B_UTF8_ELLIPSIS),
357 message);
358 item->SetTarget(window);
359 menu->AddItem(item);
362 menu->AddSeparatorItem();
363 // window settings
364 BMenu* settingsM = new BMenu(B_TRANSLATE("Settings"));
365 settingsM->SetFont(be_plain_font);
367 const char* toggleLayoutLabel;
368 if (fButtonLayout->Orientation() == B_HORIZONTAL)
369 toggleLayoutLabel = B_TRANSLATE("Vertical layout");
370 else
371 toggleLayoutLabel = B_TRANSLATE("Horizontal layout");
372 item = new BMenuItem(toggleLayoutLabel, new BMessage(MSG_TOGGLE_LAYOUT));
373 item->SetTarget(this);
374 settingsM->AddItem(item);
376 BMenu* iconSizeM = new BMenu(B_TRANSLATE("Icon size"));
377 for (uint32 i = 0; i < sizeof(kIconSizes) / sizeof(uint32); i++) {
378 uint32 iconSize = kIconSizes[i];
379 message = new BMessage(MSG_SET_ICON_SIZE);
380 message->AddInt32("size", iconSize);
381 BString label;
382 label << iconSize << " x " << iconSize;
383 item = new BMenuItem(label.String(), message);
384 item->SetTarget(this);
385 item->SetMarked(IconSize() == iconSize);
386 iconSizeM->AddItem(item);
388 settingsM->AddItem(iconSizeM);
390 item = new BMenuItem(B_TRANSLATE("Ignore double-click"),
391 new BMessage(MSG_SET_IGNORE_DOUBLECLICK));
392 item->SetTarget(this);
393 item->SetMarked(IgnoreDoubleClick());
394 settingsM->AddItem(item);
396 uint32 what = window->Look() == B_BORDERED_WINDOW_LOOK ? MSG_SHOW_BORDER : MSG_HIDE_BORDER;
397 item = new BMenuItem(B_TRANSLATE("Show window border"), new BMessage(what));
398 item->SetTarget(window);
399 item->SetMarked(what == MSG_HIDE_BORDER);
400 settingsM->AddItem(item);
402 item = new BMenuItem(B_TRANSLATE("Auto-raise"), new BMessage(MSG_TOGGLE_AUTORAISE));
403 item->SetTarget(window);
404 item->SetMarked(window->AutoRaise());
405 settingsM->AddItem(item);
407 item = new BMenuItem(B_TRANSLATE("Show on all workspaces"), new BMessage(MSG_SHOW_ON_ALL_WORKSPACES));
408 item->SetTarget(window);
409 item->SetMarked(window->ShowOnAllWorkspaces());
410 settingsM->AddItem(item);
412 menu->AddItem(settingsM);
414 menu->AddSeparatorItem();
416 // pad commands
417 BMenu* padM = new BMenu(B_TRANSLATE("Pad"));
418 padM->SetFont(be_plain_font);
419 // new pad
420 item = new BMenuItem(B_TRANSLATE("New"), new BMessage(MSG_ADD_WINDOW));
421 item->SetTarget(be_app);
422 padM->AddItem(item);
423 // new pad
424 item = new BMenuItem(B_TRANSLATE("Clone"), new BMessage(MSG_ADD_WINDOW));
425 item->SetTarget(window);
426 padM->AddItem(item);
427 padM->AddSeparatorItem();
428 // close
429 item = new BMenuItem(B_TRANSLATE("Close"), new BMessage(B_QUIT_REQUESTED));
430 item->SetTarget(window);
431 padM->AddItem(item);
432 menu->AddItem(padM);
433 // app commands
434 BMenu* appM = new BMenu(B_TRANSLATE_SYSTEM_NAME("LaunchBox"));
435 appM->SetFont(be_plain_font);
436 // quit
437 item = new BMenuItem(B_TRANSLATE("Quit"), new BMessage(B_QUIT_REQUESTED));
438 item->SetTarget(be_app);
439 appM->AddItem(item);
440 menu->AddItem(appM);
441 // finish popup
442 menu->SetAsyncAutoDestruct(true);
443 menu->SetFont(be_plain_font);
444 where = ConvertToScreen(where);
445 BRect mouseRect(where, where);
446 mouseRect.InsetBy(-4.0, -4.0);
447 menu->Go(where, true, false, mouseRect, true);
451 void
452 PadView::SetOrientation(enum orientation orientation)
454 if (orientation == B_VERTICAL) {
455 fButtonLayout->SetInsets(2, 7, 2, 2);
456 fButtonLayout->SetOrientation(B_VERTICAL);
457 } else {
458 fButtonLayout->SetInsets(7, 2, 2, 2);
459 fButtonLayout->SetOrientation(B_HORIZONTAL);
461 _NotifySettingsChanged();
465 enum orientation
466 PadView::Orientation() const
468 return fButtonLayout->Orientation();
472 void
473 PadView::SetIconSize(uint32 size)
475 if (size == fIconSize)
476 return;
478 fIconSize = size;
480 for (int32 i = 0; LaunchButton* button = ButtonAt(i); i++)
481 button->SetIconSize(fIconSize);
483 _NotifySettingsChanged();
487 uint32
488 PadView::IconSize() const
490 return fIconSize;
494 void
495 PadView::SetIgnoreDoubleClick(bool refuse)
497 LaunchButton::SetIgnoreDoubleClick(refuse);
499 _NotifySettingsChanged();
503 bool
504 PadView::IgnoreDoubleClick() const
506 return LaunchButton::IgnoreDoubleClick();
510 void
511 PadView::_NotifySettingsChanged()
513 be_app->PostMessage(MSG_SETTINGS_CHANGED);