#include "TeamMenuItem.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <Bitmap.h>
#include <ControlLook.h>
#include <Debug.h>
#include <Font.h>
#include <Mime.h>
#include <Region.h>
#include <Roster.h>
#include <Resources.h>
#include <Window.h>
#include "BarApp.h"
#include "BarMenuBar.h"
#include "BarView.h"
#include "ExpandoMenuBar.h"
#include "ResourceSet.h"
#include "ShowHideMenuItem.h"
#include "StatusView.h"
#include "TeamMenu.h"
#include "WindowMenu.h"
#include "WindowMenuItem.h"
static float sHPad, sVPad, sLabelOffset = 0.0f;
TTeamMenuItem::TTeamMenuItem(BList* team, BBitmap* icon, char* name,
char* signature, float width, float height)
:
TTruncatableMenuItem(new TWindowMenu(team, signature))
{
_Init(team, icon, name, signature, width, height);
}
TTeamMenuItem::TTeamMenuItem(float width, float height)
:
TTruncatableMenuItem("", NULL)
{
_Init(NULL, NULL, strdup(""), strdup(""), width, height);
}
TTeamMenuItem::~TTeamMenuItem()
{
delete fTeam;
delete fIcon;
free(fSignature);
}
bool
TTeamMenuItem::HandleMouseDown(BPoint where)
{
BMenu* menu = Menu();
if (menu == NULL)
return false;
BWindow* window = menu->Window();
if (window == NULL)
return false;
BMessage* message = window->CurrentMessage();
if (message == NULL)
return false;
int32 modifiers = 0;
int32 buttons = 0;
message->FindInt32("modifiers", &modifiers);
message->FindInt32("buttons", &buttons);
if ((modifiers & B_COMMAND_KEY) != 0
&& (modifiers & B_CONTROL_KEY) != 0
&& (modifiers & B_SHIFT_KEY) != 0) {
BMessage appMessage(B_SOME_APP_QUIT);
int32 teamCount = fTeam->CountItems();
BMessage quitMessage(teamCount == 1 ? B_SOME_APP_QUIT : kRemoveTeam);
quitMessage.AddInt32("itemIndex", menu->IndexOf(this));
for (int32 index = 0; index < teamCount; index++) {
team_id team = (addr_t)fTeam->ItemAt(index);
appMessage.AddInt32("be:team", team);
quitMessage.AddInt32("team", team);
kill_team(team);
}
be_app->PostMessage(&appMessage);
TExpandoMenuBar* expando = dynamic_cast<TExpandoMenuBar*>(menu);
window->PostMessage(&quitMessage, expando != NULL ? expando : menu);
return true;
} else if ((modifiers & B_SHIFT_KEY) == 0
&& (buttons & B_TERTIARY_MOUSE_BUTTON) != 0) {
be_roster->Launch(Signature());
return true;
} else if ((modifiers & B_CONTROL_KEY) != 0) {
BMessage showMessage((modifiers & B_SHIFT_KEY) != 0
? kMinimizeTeam : kBringTeamToFront);
showMessage.AddInt32("itemIndex", menu->IndexOf(this));
window->PostMessage(&showMessage, menu);
return true;
}
return false;
}
status_t
TTeamMenuItem::Invoke(BMessage* message)
{
if (fBarView != NULL) {
if (fBarView->InvokeItem(Signature())) {
return B_OK;
}
if (fBarView->Dragging())
fBarView->DragStop();
}
uint32 mods = modifiers();
if (mods & B_CONTROL_KEY) {
TShowHideMenuItem::TeamShowHideCommon((mods & B_SHIFT_KEY)
? B_MINIMIZE_WINDOW : B_BRING_TO_FRONT, Teams());
}
return BMenuItem::Invoke(message);
}
void
TTeamMenuItem::SetOverrideSelected(bool selected)
{
fOverriddenSelected = selected;
Highlight(selected);
}
void
TTeamMenuItem::SetIcon(BBitmap* icon) {
delete fIcon;
fIcon = icon;
}
void
TTeamMenuItem::GetContentSize(float* width, float* height)
{
BMenuItem::GetContentSize(width, height);
if (fOverrideWidth != -1.0f)
*width = fOverrideWidth;
else {
const float iconSize = static_cast<TBarApp*>(be_app)->TeamIconSize();
const float iconPadding = be_control_look->ComposeSpacing(kIconPadding);
float iconOnlyWidth = iconSize + iconPadding;
if (static_cast<TBarApp*>(be_app)->Settings()->hideLabels)
iconOnlyWidth += iconPadding;
if (fBarView->MiniState()) {
if (static_cast<TBarApp*>(be_app)->Settings()->hideLabels)
*width = iconOnlyWidth;
else
*width = gMinimumWindowWidth - (gDragRegionWidth + kGutter) * 2;
} else if (!fBarView->Vertical()) {
TExpandoMenuBar* menu = static_cast<TExpandoMenuBar*>(Menu());
*width = menu->MaxHorizontalItemWidth();
} else
*width = static_cast<TBarApp*>(be_app)->Settings()->width;
}
if (fOverrideHeight != -1.0f)
*height = fOverrideHeight;
else
*height = fBarView->TeamMenuItemHeight();
}
void
TTeamMenuItem::Draw()
{
BRect frame = Frame();
BMenu* menu = Menu();
menu->PushState();
rgb_color menuColor = ui_color(B_MENU_BACKGROUND_COLOR);
bool canHandle = !fBarView->Dragging()
|| fBarView->AppCanHandleTypes(Signature());
uint32 flags = 0;
if (_IsSelected() && canHandle)
flags |= BControlLook::B_ACTIVATED;
uint32 borders = BControlLook::B_TOP_BORDER;
if (fBarView->Vertical()) {
menu->SetHighColor(tint_color(menuColor, B_DARKEN_1_TINT));
borders |= BControlLook::B_LEFT_BORDER
| BControlLook::B_RIGHT_BORDER;
menu->StrokeLine(frame.LeftBottom(), frame.RightBottom());
frame.bottom--;
be_control_look->DrawMenuBarBackground(menu, frame, frame,
menuColor, flags, borders);
} else {
if (flags & BControlLook::B_ACTIVATED)
menu->SetHighColor(tint_color(menuColor, B_DARKEN_3_TINT));
else
menu->SetHighColor(tint_color(menuColor, 1.22));
borders |= BControlLook::B_BOTTOM_BORDER;
menu->StrokeLine(frame.LeftTop(), frame.LeftBottom());
frame.left++;
be_control_look->DrawButtonBackground(menu, frame, frame,
menuColor, flags, borders);
}
menu->MovePenTo(ContentLocation());
DrawContent();
menu->PopState();
}
void
TTeamMenuItem::DrawContent()
{
BMenu* menu = Menu();
BRect frame = Frame();
if (fIcon != NULL) {
if (fIcon->ColorSpace() == B_RGBA32) {
menu->SetDrawingMode(B_OP_ALPHA);
menu->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
} else
menu->SetDrawingMode(B_OP_OVER);
BRect iconBounds = fIcon->Bounds();
BRect updateRect = iconBounds;
BPoint contentLocation = ContentLocation();
BPoint drawLocation = contentLocation + BPoint(sHPad, sVPad);
const int32 large = be_control_look->ComposeIconSize(B_LARGE_ICON)
.IntegerWidth() + 1;
if (static_cast<TBarApp*>(be_app)->Settings()->hideLabels
|| (fBarView->Vertical() && iconBounds.Width() > large)) {
float offsetx = contentLocation.x
+ floorf((frame.Width() - iconBounds.Width()) / 2);
float offsety = contentLocation.y + sVPad + kGutter;
updateRect.OffsetTo(BPoint(offsetx, offsety));
menu->DrawBitmapAsync(fIcon, updateRect);
drawLocation.x = floorf((frame.Width() - fLabelWidth) / 2);
drawLocation.y = frame.top + sVPad + iconBounds.Height() + sVPad;
} else {
float offsetx = contentLocation.x + sHPad;
float offsety = contentLocation.y +
floorf((frame.Height() - iconBounds.Height()) / 2);
updateRect.OffsetTo(BPoint(offsetx, offsety));
menu->DrawBitmapAsync(fIcon, updateRect);
drawLocation.x += iconBounds.Width() + sLabelOffset;
drawLocation.y = frame.top
+ ceilf((frame.Height() - fLabelHeight) / 2);
}
menu->MovePenTo(drawLocation);
}
menu->SetDrawingMode(B_OP_OVER);
menu->SetHighColor(ui_color(B_MENU_ITEM_TEXT_COLOR));
bool canHandle = !fBarView->Dragging()
|| fBarView->AppCanHandleTypes(Signature());
if (_IsSelected() && IsEnabled() && canHandle)
menu->SetLowColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR),
B_HIGHLIGHT_BACKGROUND_TINT));
else
menu->SetLowColor(ui_color(B_MENU_BACKGROUND_COLOR));
if (IsSelected())
menu->SetHighColor(ui_color(B_MENU_SELECTED_ITEM_TEXT_COLOR));
else
menu->SetHighColor(ui_color(B_MENU_ITEM_TEXT_COLOR));
menu->MovePenBy(0, fLabelAscent);
if (!static_cast<TBarApp*>(be_app)->Settings()->hideLabels) {
float labelWidth = menu->StringWidth(Label());
BPoint penLocation = menu->PenLocation();
float offset = penLocation.x - frame.left;
menu->DrawString(Label(labelWidth + offset));
}
if (fBarView->Vertical()
&& static_cast<TBarApp*>(be_app)->Settings()->superExpando
&& fBarView->ExpandoState()) {
DrawExpanderArrow();
}
}
void
TTeamMenuItem::DrawExpanderArrow()
{
BRect frame = Frame();
BRect rect(0.0f, 0.0f, kSwitchWidth, sHPad + 2.0f);
rect.OffsetTo(BPoint(frame.right - rect.Width(),
ContentLocation().y + ((frame.Height() - rect.Height()) / 2)));
float colorTint = B_DARKEN_3_TINT;
rgb_color bgColor = ui_color(B_MENU_BACKGROUND_COLOR);
if (bgColor.red + bgColor.green + bgColor.blue <= 128 * 3)
colorTint = B_LIGHTEN_2_TINT;
be_control_look->DrawArrowShape(Menu(), rect, Menu()->Frame(),
bgColor, fArrowDirection, 0, colorTint);
}
void
TTeamMenuItem::ToggleExpandState(bool resizeWindow)
{
fExpanded = !fExpanded;
fArrowDirection = fExpanded ? BControlLook::B_DOWN_ARROW
: BControlLook::B_RIGHT_ARROW;
if (fExpanded) {
TWindowMenu* sub = (static_cast<TWindowMenu*>(Submenu()));
if (sub != NULL) {
bool locked = sub->LockLooper();
sub->AttachedToWindow();
if (locked)
sub->UnlockLooper();
if (sub->CountItems() > 1) {
TExpandoMenuBar* parent = static_cast<TExpandoMenuBar*>(Menu());
int myindex = parent->IndexOf(this) + 1;
TWindowMenuItem* windowItem = NULL;
int32 childIndex = 0;
int32 totalChildren = sub->CountItems() - 4;
for (; childIndex < totalChildren; childIndex++) {
windowItem = static_cast<TWindowMenuItem*>
(sub->RemoveItem((int32)0));
parent->AddItem(windowItem, myindex + childIndex);
windowItem->SetExpanded(true);
}
sub->SetExpanded(true, myindex + childIndex);
if (resizeWindow)
parent->SizeWindow(-1);
}
}
} else {
TWindowMenu* sub = static_cast<TWindowMenu*>(Submenu());
if (sub != NULL) {
TExpandoMenuBar* parent = static_cast<TExpandoMenuBar*>(Menu());
TWindowMenuItem* windowItem = NULL;
int32 childIndex = parent->IndexOf(this) + 1;
while (parent->SubmenuAt(childIndex) == NULL
&& childIndex < parent->CountItems()) {
windowItem = static_cast<TWindowMenuItem*>(
parent->RemoveItem(childIndex));
sub->AddItem(windowItem, 0);
windowItem->SetExpanded(false);
}
sub->SetExpanded(false, 0);
if (resizeWindow)
parent->SizeWindow(1);
}
}
}
TWindowMenuItem*
TTeamMenuItem::ExpandedWindowItem(int32 id)
{
if (!fExpanded) {
return NULL;
}
TExpandoMenuBar* parent = static_cast<TExpandoMenuBar*>(Menu());
int childIndex = parent->IndexOf(this) + 1;
while (!parent->SubmenuAt(childIndex)
&& childIndex < parent->CountItems()) {
TWindowMenuItem* item
= static_cast<TWindowMenuItem*>(parent->ItemAt(childIndex));
if (item->ID() == id)
return item;
childIndex++;
}
return NULL;
}
BRect
TTeamMenuItem::ExpanderBounds() const
{
BRect bounds(Frame());
bounds.left = bounds.right - kSwitchWidth;
return bounds;
}
void
TTeamMenuItem::_Init(BList* team, BBitmap* icon, char* name, char* signature,
float width, float height)
{
if (sHPad == 0.0f) {
sHPad = be_control_look->ComposeSpacing(B_USE_SMALL_SPACING);
sVPad = ceilf(be_control_look->ComposeSpacing(B_USE_SMALL_SPACING) / 4.0f);
sLabelOffset = ceilf((be_control_look->DefaultLabelSpacing() / 3.0f) * 4.0f);
}
fTeam = team;
fIcon = icon;
fSignature = signature;
if (name == NULL) {
char temp[32];
snprintf(temp, sizeof(temp), "team %ld", (addr_t)team->ItemAt(0));
name = strdup(temp);
}
SetLabel(name);
fOverrideWidth = width;
fOverrideHeight = height;
fBarView = static_cast<TBarApp*>(be_app)->BarView();
menu_info info;
get_menu_info(&info);
BFont font;
font.SetFamilyAndStyle(info.f_family, info.f_style);
font.SetSize(info.font_size);
fLabelWidth = ceilf(font.StringWidth(name));
font_height fontHeight;
font.GetHeight(&fontHeight);
fLabelAscent = ceilf(fontHeight.ascent);
fLabelDescent = ceilf(fontHeight.descent + fontHeight.leading);
fLabelHeight = fLabelAscent + fLabelDescent;
fOverriddenSelected = false;
fExpanded = false;
fArrowDirection = BControlLook::B_RIGHT_ARROW;
}
bool
TTeamMenuItem::_IsSelected() const
{
return IsSelected() || fOverriddenSelected;
}