Files
haiku-beta6/src/kits/interface/MenuField.cpp
T

670 lines
11 KiB
C++
Raw Normal View History

2005-11-09 22:25:34 +00:00
/*
2006-02-16 15:17:41 +00:00
* Copyright 2001-2006, Haiku, Inc.
2005-11-09 22:25:34 +00:00
* Distributed under the terms of the MIT License.
*
* Authors:
* Marc Flerackers ([email protected])
2006-02-16 15:17:41 +00:00
* Stephan Aßmus <[email protected]>
2005-11-09 22:25:34 +00:00
*/
2004-06-27 21:36:42 +00:00
#include <stdlib.h>
#include <string.h>
2003-06-16 08:32:55 +00:00
#include <MenuBar.h>
#include <MenuField.h>
#include <Message.h>
#include <BMCPrivate.h>
#include <Window.h>
static float kVMargin = 2.0f;
2005-11-09 22:25:34 +00:00
2003-06-16 08:32:55 +00:00
BMenuField::BMenuField(BRect frame, const char *name, const char *label,
2005-11-09 22:25:34 +00:00
BMenu *menu, uint32 resize, uint32 flags)
: BView(frame, name, resize, flags)
2003-06-16 08:32:55 +00:00
{
InitObject(label);
SetFont(be_plain_font);
fMenu = menu;
InitMenu(menu);
frame.OffsetTo(B_ORIGIN);
fMenuBar = new _BMCMenuBar_(BRect(frame.left + fDivider + 1,
frame.top + kVMargin, frame.right, frame.bottom - kVMargin),
2003-06-16 08:32:55 +00:00
false, this);
AddChild(fMenuBar);
fMenuBar->AddItem(menu);
2003-06-16 08:32:55 +00:00
fMenuBar->SetFont(be_plain_font);
InitObject2();
}
2005-11-09 22:25:34 +00:00
2003-06-16 08:32:55 +00:00
BMenuField::BMenuField(BRect frame, const char *name, const char *label,
2005-11-09 22:25:34 +00:00
BMenu *menu, bool fixedSize, uint32 resize, uint32 flags)
: BView(frame, name, resize, flags)
2003-06-16 08:32:55 +00:00
{
InitObject(label);
SetFont(be_plain_font);
fMenu = menu;
InitMenu(menu);
2005-11-09 22:25:34 +00:00
fFixedSizeMB = fixedSize;
2003-06-16 08:32:55 +00:00
frame.OffsetTo(B_ORIGIN);
fMenuBar = new _BMCMenuBar_(BRect(frame.left + fDivider + 1,
frame.top + kVMargin, frame.right, frame.bottom - kVMargin),
2005-11-09 22:25:34 +00:00
fixedSize, this);
2003-06-16 08:32:55 +00:00
AddChild(fMenuBar);
fMenuBar->AddItem(menu);
2003-06-16 08:32:55 +00:00
fMenuBar->SetFont(be_plain_font);
InitObject2();
}
2005-11-09 22:25:34 +00:00
2003-06-16 08:32:55 +00:00
BMenuField::BMenuField(BMessage *data)
2005-11-09 22:25:34 +00:00
: BView(data)
2003-06-16 08:32:55 +00:00
{
const char *label = NULL;
data->FindString("_label", &label);
2005-11-09 22:25:34 +00:00
2003-06-16 08:32:55 +00:00
InitObject(label);
fMenuBar = (BMenuBar*)FindView("_mc_mb_");
fMenu = fMenuBar->SubmenuAt(0);
InitObject2();
bool disable;
if (data->FindBool("_disable", &disable) == B_OK)
SetEnabled(!disable);
int32 align;
data->FindInt32("_align", &align);
SetAlignment((alignment)align);
data->FindFloat("_divide", &fDivider);
bool fixed;
if (data->FindBool("be:fixeds", &fixed) == B_OK)
fFixedSizeMB = fixed;
// BMenuItem *item = fMenuBar->ItemAt(0);
// if (!item)
// return;
//
// _BMCItem_ *bmcitem = dynamic_cast<_BMCItem_*>(item);
// if (!bmcitem)
// return;
//
// bool dmark;
// if (data->FindBool("be:dmark", &dmark))
// bmcitem->fShowPopUpMarker = dmark;
2003-06-16 08:32:55 +00:00
}
2005-11-09 22:25:34 +00:00
2003-06-16 08:32:55 +00:00
BMenuField::~BMenuField()
{
2005-11-09 22:25:34 +00:00
free(fLabel);
2003-06-16 08:32:55 +00:00
status_t dummy;
2003-06-16 08:32:55 +00:00
if (fMenuTaskID >= 0)
wait_for_thread(fMenuTaskID, &dummy);
2003-06-16 08:32:55 +00:00
}
2005-11-09 22:25:34 +00:00
BArchivable *
BMenuField::Instantiate(BMessage *data)
2003-06-16 08:32:55 +00:00
{
if (validate_instantiation(data, "BMenuField"))
return new BMenuField(data);
2005-11-09 22:25:34 +00:00
return NULL;
2003-06-16 08:32:55 +00:00
}
2005-11-09 22:25:34 +00:00
status_t
BMenuField::Archive(BMessage *data, bool deep) const
2003-06-16 08:32:55 +00:00
{
BView::Archive(data, deep);
if (Label())
data->AddString("_label", Label());
if (!IsEnabled())
data->AddBool("_disable", true);
data->AddInt32("_align", Alignment());
data->AddFloat("_divide", Divider());
if (fFixedSizeMB)
data->AddBool("be:fixeds", true);
// BMenuItem *item = fMenuBar->ItemAt(0);
// if (!item)
// return B_OK;
//
// _BMCItem_ *bmcitem = dynamic_cast<_BMCItem_*>(item);
// if (bmcitem && !bmcitem->fShowPopUpMarker)
// data->AddBool("be:dmark", false);
2003-06-16 08:32:55 +00:00
return B_OK;
}
2005-11-09 22:25:34 +00:00
void
BMenuField::Draw(BRect update)
2003-06-16 08:32:55 +00:00
{
BRect bounds(Bounds());
bool active = false;
if (IsFocus())
active = Window()->IsActive();
DrawLabel(bounds, update);
BRect frame(fMenuBar->Frame());
2006-02-16 15:17:41 +00:00
if (frame.InsetByCopy(-kVMargin, -kVMargin).Intersects(update)) {
2003-06-16 08:32:55 +00:00
SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_DARKEN_2_TINT));
StrokeLine(BPoint(frame.left - 1.0f, frame.top - 1.0f),
BPoint(frame.left - 1.0f, frame.bottom - 1.0f));
StrokeLine(BPoint(frame.left - 1.0f, frame.top - 1.0f),
BPoint(frame.right - 1.0f, frame.top - 1.0f));
StrokeLine(BPoint(frame.left + 1.0f, frame.bottom + 1.0f),
BPoint(frame.right + 1.0f, frame.bottom + 1.0f));
StrokeLine(BPoint(frame.right + 1.0f, frame.top + 1.0f));
SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_DARKEN_4_TINT));
StrokeLine(BPoint(frame.left - 1.0f, frame.bottom),
BPoint(frame.left - 1.0f, frame.bottom));
StrokeLine(BPoint(frame.right, frame.top - 1.0f),
BPoint(frame.right, frame.top - 1.0f));
}
2005-11-09 22:25:34 +00:00
if (active || fTransition) {
2003-06-16 08:32:55 +00:00
SetHighColor(active ? ui_color(B_KEYBOARD_NAVIGATION_COLOR) :
ViewColor());
StrokeRect(frame.InsetByCopy(-kVMargin, -kVMargin));
fTransition = false;
}
}
2005-11-09 22:25:34 +00:00
void
BMenuField::AttachedToWindow()
2003-06-16 08:32:55 +00:00
{
2005-11-09 22:25:34 +00:00
if (Parent()) {
2003-06-16 08:32:55 +00:00
SetViewColor(Parent()->ViewColor());
SetLowColor(Parent()->ViewColor());
}
if (fLabel)
2005-11-09 22:25:34 +00:00
fStringWidth = StringWidth(fLabel);
2003-06-16 08:32:55 +00:00
}
2005-11-09 22:25:34 +00:00
void
BMenuField::AllAttached()
2003-06-16 08:32:55 +00:00
{
ResizeTo(Bounds().Width(),
fMenuBar->Bounds().Height() + kVMargin + kVMargin);
}
2005-11-09 22:25:34 +00:00
void
BMenuField::MouseDown(BPoint where)
2003-06-16 08:32:55 +00:00
{
if (!IsEnabled() || (where.x > fDivider && !fMenuBar->Frame().Contains(where)))
2003-06-16 08:32:55 +00:00
return;
2004-06-27 21:36:42 +00:00
BRect bounds = fMenuBar->ConvertFromParent(Bounds());
2003-06-16 08:32:55 +00:00
2004-06-27 21:36:42 +00:00
fMenuBar->StartMenuBar(0, false, true, &bounds);
2003-06-16 08:32:55 +00:00
fMenuTaskID = spawn_thread((thread_func)MenuTask, "_m_task_",
B_NORMAL_PRIORITY, this);
if (fMenuTaskID)
resume_thread(fMenuTaskID);
}
2005-11-09 22:25:34 +00:00
void
BMenuField::KeyDown(const char *bytes, int32 numBytes)
2003-06-16 08:32:55 +00:00
{
2005-11-09 22:25:34 +00:00
switch (bytes[0]) {
2003-06-16 08:32:55 +00:00
case B_SPACE:
case B_RIGHT_ARROW:
case B_DOWN_ARROW:
{
if (!IsEnabled())
break;
2004-06-27 21:36:42 +00:00
BRect bounds = fMenuBar->ConvertFromParent(Bounds());
2003-06-16 08:32:55 +00:00
2004-06-27 21:36:42 +00:00
fMenuBar->StartMenuBar(0, true, true, &bounds);
2003-06-16 08:32:55 +00:00
fSelected = true;
fTransition = true;
bounds = Bounds();
bounds.right = fDivider;
Invalidate(bounds);
2003-06-16 08:32:55 +00:00
}
2005-11-09 22:25:34 +00:00
2003-06-16 08:32:55 +00:00
default:
BView::KeyDown(bytes, numBytes);
}
}
2005-11-09 22:25:34 +00:00
void
BMenuField::MakeFocus(bool state)
2003-06-16 08:32:55 +00:00
{
if (IsFocus() == state)
return;
BView::MakeFocus(state);
if (Window())
Invalidate(); // TODO: use fStringWidth
2003-06-16 08:32:55 +00:00
}
2005-11-09 22:25:34 +00:00
void
BMenuField::MessageReceived(BMessage *msg)
2003-06-16 08:32:55 +00:00
{
BView::MessageReceived(msg);
}
2005-11-09 22:25:34 +00:00
void
BMenuField::WindowActivated(bool state)
2003-06-16 08:32:55 +00:00
{
BView::WindowActivated(state);
if (IsFocus())
Invalidate();
2003-06-16 08:32:55 +00:00
}
2005-11-09 22:25:34 +00:00
void
BMenuField::MouseUp(BPoint point)
2003-06-16 08:32:55 +00:00
{
2005-11-09 22:25:34 +00:00
BView::MouseUp(point);
2003-06-16 08:32:55 +00:00
}
2005-11-09 22:25:34 +00:00
void
BMenuField::MouseMoved(BPoint point, uint32 code, const BMessage *message)
2003-06-16 08:32:55 +00:00
{
2005-11-09 22:25:34 +00:00
BView::MouseMoved(point, code, message);
2003-06-16 08:32:55 +00:00
}
2005-11-09 22:25:34 +00:00
void
BMenuField::DetachedFromWindow()
2003-06-16 08:32:55 +00:00
{
BView::DetachedFromWindow();
}
2005-11-09 22:25:34 +00:00
void
BMenuField::AllDetached()
2003-06-16 08:32:55 +00:00
{
BView::AllDetached();
}
2005-11-09 22:25:34 +00:00
void
BMenuField::FrameMoved(BPoint newPosition)
2003-06-16 08:32:55 +00:00
{
2005-11-09 22:25:34 +00:00
BView::FrameMoved(newPosition);
2003-06-16 08:32:55 +00:00
}
2005-11-09 22:25:34 +00:00
void
BMenuField::FrameResized(float newWidth, float newHeight)
2003-06-16 08:32:55 +00:00
{
2005-11-09 22:25:34 +00:00
BView::FrameResized(newWidth, newHeight);
2003-06-16 08:32:55 +00:00
}
2005-11-09 22:25:34 +00:00
BMenu *
BMenuField::Menu() const
2003-06-16 08:32:55 +00:00
{
return fMenu;
}
2005-11-09 22:25:34 +00:00
BMenuBar *
BMenuField::MenuBar() const
2003-06-16 08:32:55 +00:00
{
return fMenuBar;
}
2005-11-09 22:25:34 +00:00
BMenuItem *
BMenuField::MenuItem() const
2003-06-16 08:32:55 +00:00
{
return fMenuBar->ItemAt(0);
}
2005-11-09 22:25:34 +00:00
void
BMenuField::SetLabel(const char *label)
2003-06-16 08:32:55 +00:00
{
2005-11-09 22:25:34 +00:00
if (fLabel) {
2003-06-16 08:32:55 +00:00
if (label && strcmp(fLabel, label) == 0)
return;
free(fLabel);
}
fLabel = strdup(label);
2005-11-09 22:25:34 +00:00
if (Window()) {
2003-06-16 08:32:55 +00:00
Invalidate();
if (fLabel)
fStringWidth = StringWidth(fLabel);
}
}
2005-11-09 22:25:34 +00:00
const char *
BMenuField::Label() const
2003-06-16 08:32:55 +00:00
{
return fLabel;
}
2005-11-09 22:25:34 +00:00
void
BMenuField::SetEnabled(bool on)
2003-06-16 08:32:55 +00:00
{
if (fEnabled == on)
return;
fEnabled = on;
fMenuBar->SetEnabled(on);
2005-11-09 22:25:34 +00:00
if (Window()) {
2003-06-16 08:32:55 +00:00
fMenuBar->Invalidate(fMenuBar->Bounds());
Invalidate(Bounds());
}
}
2005-11-09 22:25:34 +00:00
bool
BMenuField::IsEnabled() const
2003-06-16 08:32:55 +00:00
{
return fEnabled;
}
2005-11-09 22:25:34 +00:00
void
BMenuField::SetAlignment(alignment label)
2003-06-16 08:32:55 +00:00
{
fAlign = label;
}
2005-11-09 22:25:34 +00:00
alignment
BMenuField::Alignment() const
2003-06-16 08:32:55 +00:00
{
return fAlign;
}
2005-11-09 22:25:34 +00:00
void
BMenuField::SetDivider(float divider)
2003-06-16 08:32:55 +00:00
{
divider = floorf(divider + 0.5);
float dx = fDivider - divider;
if (dx == 0.0f)
2003-06-16 08:32:55 +00:00
return;
fDivider = divider;
2003-06-16 08:32:55 +00:00
MenuBar()->MoveBy(-dx, 0.0f);
MenuBar()->ResizeBy(dx, 0.0f);
2003-06-16 08:32:55 +00:00
}
2005-11-09 22:25:34 +00:00
float
BMenuField::Divider() const
2003-06-16 08:32:55 +00:00
{
return fDivider;
}
2005-11-09 22:25:34 +00:00
void
BMenuField::ShowPopUpMarker()
2003-06-16 08:32:55 +00:00
{
// TODO:
}
2005-11-09 22:25:34 +00:00
void
BMenuField::HidePopUpMarker()
2003-06-16 08:32:55 +00:00
{
// TODO:
}
2005-11-09 22:25:34 +00:00
BHandler *
BMenuField::ResolveSpecifier(BMessage *message, int32 index,
BMessage *specifier, int32 form, const char *property)
2003-06-16 08:32:55 +00:00
{
2005-11-09 22:25:34 +00:00
return BView::ResolveSpecifier(message, index, specifier, form, property);
2003-06-16 08:32:55 +00:00
}
2005-11-09 22:25:34 +00:00
status_t
BMenuField::GetSupportedSuites(BMessage *data)
2003-06-16 08:32:55 +00:00
{
return BView::GetSupportedSuites(data);
}
2005-11-09 22:25:34 +00:00
void
BMenuField::ResizeToPreferred()
2003-06-16 08:32:55 +00:00
{
2006-02-16 15:17:41 +00:00
fMenuBar->ResizeToPreferred();
2003-06-16 08:32:55 +00:00
BView::ResizeToPreferred();
}
2005-11-09 22:25:34 +00:00
void
BMenuField::GetPreferredSize(float *_width, float *_height)
{
2006-02-16 15:17:41 +00:00
fMenuBar->GetPreferredSize(_width, _height);
2006-02-16 15:17:41 +00:00
if (_width) {
// the width is already the menu bars preferred width
// add the room we need to draw the shadow and stuff
*_width += 2 * kVMargin;
2006-02-16 15:17:41 +00:00
// add the room needed for the label
float labelWidth = fDivider;
if (Label()) {
labelWidth = ceilf(StringWidth(Label()));
if (labelWidth > 0.0) {
// add some room between label and menu bar
labelWidth += 5.0;
}
// have divider override the calculated label width
labelWidth = max_c(labelWidth, fDivider);
}
*_width += labelWidth;
}
2006-02-16 15:17:41 +00:00
if (_height) {
// the height is already the menu bars preferred height
// add the room we need to draw the shadow and stuff
*_height += 2 * kVMargin;
// see if our label would fit vertically
font_height fh;
GetFontHeight(&fh);
*_height = max_c(*_height, ceilf(fh.ascent + fh.descent));
}
2003-06-16 08:32:55 +00:00
}
2005-11-09 22:25:34 +00:00
status_t
BMenuField::Perform(perform_code d, void *arg)
2003-06-16 08:32:55 +00:00
{
return BView::Perform(d, arg);
}
2005-11-09 22:25:34 +00:00
2003-06-16 08:32:55 +00:00
void BMenuField::_ReservedMenuField1() {}
void BMenuField::_ReservedMenuField2() {}
void BMenuField::_ReservedMenuField3() {}
2005-11-09 22:25:34 +00:00
BMenuField &
BMenuField::operator=(const BMenuField &)
2003-06-16 08:32:55 +00:00
{
return *this;
}
2005-11-09 22:25:34 +00:00
void
BMenuField::InitObject(const char *label)
2003-06-16 08:32:55 +00:00
{
fLabel = NULL;
fMenu = NULL;
fMenuBar = NULL;
2003-06-16 08:32:55 +00:00
fAlign = B_ALIGN_LEFT;
fStringWidth = 0;
fEnabled = true;
fSelected = false;
fTransition = false;
fFixedSizeMB = false;
fMenuTaskID = -1;
SetLabel(label);
if (label)
fDivider = (float)floor(Frame().Width() / 2.0f);
else
fDivider = 0;
}
2005-11-09 22:25:34 +00:00
void
BMenuField::InitObject2()
2003-06-16 08:32:55 +00:00
{
// TODO set filter
font_height fontHeight;
GetFontHeight(&fontHeight);
// TODO: fix this calculation
float height = floorf(fontHeight.ascent + fontHeight.descent
+ fontHeight.leading) + 7;
fMenuBar->ResizeTo(Bounds().Width() - fDivider, height);
2003-06-16 08:32:55 +00:00
}
2005-11-09 22:25:34 +00:00
void
BMenuField::DrawLabel(BRect bounds, BRect update)
2003-06-16 08:32:55 +00:00
{
font_height fh;
GetFontHeight(&fh);
2005-11-09 22:25:34 +00:00
if (Label()) {
2003-06-16 08:32:55 +00:00
SetLowColor(ViewColor());
float y = (float)ceil(fh.ascent + fh.descent + fh.leading) + 2.0f;
float x;
2005-11-09 22:25:34 +00:00
switch (fAlign) {
2003-06-16 08:32:55 +00:00
case B_ALIGN_RIGHT:
x = fDivider - StringWidth(Label()) - 3.0f;
break;
case B_ALIGN_CENTER:
x = fDivider - StringWidth(Label()) / 2.0f;
break;
default:
x = 3.0f;
break;
}
2005-11-09 22:25:34 +00:00
2003-06-16 08:32:55 +00:00
SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
2005-11-09 22:25:34 +00:00
IsEnabled() ? B_DARKEN_MAX_TINT : B_DISABLED_LABEL_TINT));
2003-06-16 08:32:55 +00:00
DrawString(Label(), BPoint(x, y));
}
}
2005-11-09 22:25:34 +00:00
void
BMenuField::InitMenu(BMenu *menu)
2003-06-16 08:32:55 +00:00
{
menu->SetFont(be_plain_font);
int32 index = 0;
BMenu *subMenu;
2004-06-27 21:36:42 +00:00
while ((subMenu = menu->SubmenuAt(index++)) != NULL)
2003-06-16 08:32:55 +00:00
InitMenu(subMenu);
}
2005-11-09 22:25:34 +00:00
long
BMenuField::MenuTask(void *arg)
2003-06-16 08:32:55 +00:00
{
BMenuField *menuField = (BMenuField*)arg;
if (!menuField->LockLooper())
return 0;
menuField->fSelected = true;
menuField->fTransition = true;
menuField->Invalidate();
2003-06-16 08:32:55 +00:00
menuField->UnlockLooper();
bool tracking;
do {
2003-06-16 08:32:55 +00:00
snooze(20000);
if (!menuField->LockLooper())
return 0;
tracking = menuField->fMenuBar->fTracking;
menuField->UnlockLooper();
} while (tracking);
if (!menuField->LockLooper())
return 0;
menuField->fSelected = false;
menuField->fTransition = true;
menuField->Invalidate();
2003-06-16 08:32:55 +00:00
menuField->UnlockLooper();
return 0;
}