Changed the interaction between BMenuFrame, BMenuScroller and

BMenuWindow. BMenuScroller now is just the scroller button, and it's a 
child of BMenuWindow. This simplifies attaching/detaching the 
scrollers, and it's also a bit cleaner. 
The lower scroller wasn't shown anymore for some reason, and this commit also fixes this problem.
A drawing bug shows up now, though: when scrolling the menu UP, some 
spurious lines are drawn over the menu. I wonder if this is an 
app_server bug or what.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21326 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stefano Ceccherini
2007-06-05 10:20:06 +00:00
parent 7d6047f97c
commit 3616859a05
2 changed files with 185 additions and 137 deletions
+8 -1
View File
@@ -35,8 +35,15 @@ class BMenuWindow : public BWindow {
bool CheckForScrolling(BPoint cursor); bool CheckForScrolling(BPoint cursor);
private: private:
BMenuScroller *fScroller; BMenu *fMenu;
BMenuFrame *fMenuFrame; BMenuFrame *fMenuFrame;
BMenuScroller *fUpperScroller;
BMenuScroller *fLowerScroller;
float fValue;
float fLimit;
bool _Scroll(BPoint cursor);
}; };
} // namespace BPrivate } // namespace BPrivate
+172 -131
View File
@@ -20,44 +20,45 @@ namespace BPrivate {
class BMenuScroller : public BView { class BMenuScroller : public BView {
public: public:
BMenuScroller(BRect frame, BMenu *menu); BMenuScroller(BRect frame);
virtual ~BMenuScroller();
virtual void Draw(BRect updateRect);
bool Scroll(BPoint cursor);
bool IsEnabled() const;
void SetEnabled(const bool &enabled);
private: private:
BMenu *fMenu; bool fEnabled;
BRect fUpperButton;
BRect fLowerButton;
float fValue;
float fLimit;
bool fUpperEnabled;
bool fLowerEnabled;
uint32 fButton;
BPoint fPosition;
}; };
class BMenuFrame : public BView { class BMenuFrame : public BView {
public: public:
BMenuFrame(BMenu *menu); BMenuFrame(BMenu *menu);
virtual ~BMenuFrame();
virtual void AttachedToWindow(); virtual void AttachedToWindow();
virtual void DetachedFromWindow(); virtual void DetachedFromWindow();
virtual void Draw(BRect updateRect); virtual void Draw(BRect updateRect);
private: private:
friend class BMenuWindow; friend class BMenuWindow;
BMenu *fMenu; BMenu *fMenu;
}; };
class UpperScroller : public BMenuScroller {
public:
UpperScroller(BRect frame);
virtual void Draw(BRect updateRect);
};
class LowerScroller : public BMenuScroller {
public:
LowerScroller(BRect frame);
virtual void Draw(BRect updateRect);
};
} // namespace BPrivate } // namespace BPrivate
using namespace BPrivate; using namespace BPrivate;
@@ -65,113 +66,89 @@ const int kScrollerHeight = 10;
const int kScrollStep = 19; const int kScrollStep = 19;
BMenuScroller::BMenuScroller(BRect frame, BMenu *menu) BMenuScroller::BMenuScroller(BRect frame)
: BView(frame, "menu scroller", 0, B_WILL_DRAW | B_FRAME_EVENTS), : BView(frame, "menu scroller", 0, B_WILL_DRAW | B_FRAME_EVENTS),
fMenu(menu), fEnabled(false)
fUpperButton(0, 0, frame.right, kScrollerHeight),
fLowerButton(0, frame.bottom - kScrollerHeight, frame.right, frame.bottom),
fValue(0),
fUpperEnabled(false),
fLowerEnabled(true)
{ {
if (!menu)
debugger("BMenuScroller(): Scroller not attached to a menu!");
SetViewColor(ui_color(B_MENU_BACKGROUND_COLOR)); SetViewColor(ui_color(B_MENU_BACKGROUND_COLOR));
fLimit = menu->Bounds().Height() - (frame.Height() - 2 * kScrollerHeight);
}
BMenuScroller::~BMenuScroller()
{
} }
bool bool
BMenuScroller::Scroll(BPoint cursor) BMenuScroller::IsEnabled() const
{ {
ConvertFromScreen(&cursor); return fEnabled;
if (fLowerEnabled && fLowerButton.Contains(cursor)) {
if (fValue == 0) {
fUpperEnabled = true;
Invalidate(fUpperButton);
}
if (fValue + kScrollStep >= fLimit) {
// If we reached the limit, we don't want to scroll a whole
// 'step' if not needed.
fMenu->ScrollBy(0, fLimit - fValue);
fValue = fLimit;
fLowerEnabled = false;
Invalidate(fLowerButton);
} else {
fMenu->ScrollBy(0, kScrollStep);
fValue += kScrollStep;
}
} else if (fUpperEnabled && fUpperButton.Contains(cursor)) {
if (fValue == fLimit) {
fLowerEnabled = true;
Invalidate(fLowerButton);
}
if (fValue - kScrollStep <= 0) {
fMenu->ScrollBy(0, -fValue);
fValue = 0;
fUpperEnabled = false;
Invalidate(fUpperButton);
} else {
fMenu->ScrollBy(0, -kScrollStep);
fValue -= kScrollStep;
}
} else {
return false;
}
snooze(10000);
return true;
} }
void void
BMenuScroller::Draw(BRect updateRect) BMenuScroller::SetEnabled(const bool &enabled)
{
fEnabled = enabled;
}
// #pragma mark -
UpperScroller::UpperScroller(BRect frame)
:
BMenuScroller(frame)
{
}
void
UpperScroller::Draw(BRect updateRect)
{ {
SetLowColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_DARKEN_1_TINT)); SetLowColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_DARKEN_1_TINT));
float middle = Bounds().right / 2; float middle = Bounds().right / 2;
// Draw the upper arrow. // Draw the upper arrow.
if (updateRect.Intersects(fUpperButton)) { if (IsEnabled())
if (fUpperEnabled) SetHighColor(0, 0, 0);
SetHighColor(0, 0, 0); else
else SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR),
SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_DARKEN_2_TINT));
B_DARKEN_2_TINT));
FillRect(fUpperButton, B_SOLID_LOW); FillRect(Bounds(), B_SOLID_LOW);
FillTriangle(BPoint(middle, (kScrollerHeight / 2) - 3), FillTriangle(BPoint(middle, (kScrollerHeight / 2) - 3),
BPoint(middle + 5, (kScrollerHeight / 2) + 2), BPoint(middle + 5, (kScrollerHeight / 2) + 2),
BPoint(middle - 5, (kScrollerHeight / 2) + 2)); BPoint(middle - 5, (kScrollerHeight / 2) + 2));
} }
// #pragma mark -
LowerScroller::LowerScroller(BRect frame)
:
BMenuScroller(frame)
{
}
void
LowerScroller::Draw(BRect updateRect)
{
SetLowColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_DARKEN_1_TINT));
BRect frame = Bounds();
// Draw the lower arrow. // Draw the lower arrow.
if (updateRect.Intersects(fLowerButton)) { if (IsEnabled())
if (fLowerEnabled) SetHighColor(0, 0, 0);
SetHighColor(0, 0, 0); else
else SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR),
SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_DARKEN_2_TINT));
B_DARKEN_2_TINT));
FillRect(fLowerButton, B_SOLID_LOW); FillRect(Bounds(), B_SOLID_LOW);
FillTriangle(BPoint(middle, fLowerButton.bottom - (kScrollerHeight / 2) + 3), float middle = Bounds().right / 2;
BPoint(middle + 5, fLowerButton.bottom - (kScrollerHeight / 2) - 2),
BPoint(middle - 5, fLowerButton.bottom - (kScrollerHeight / 2) - 2)); FillTriangle(BPoint(middle, frame.bottom - (kScrollerHeight / 2) + 3),
} BPoint(middle + 5, frame.bottom - (kScrollerHeight / 2) - 2),
BPoint(middle - 5, frame.bottom - (kScrollerHeight / 2) - 2));
} }
@@ -185,11 +162,6 @@ BMenuFrame::BMenuFrame(BMenu *menu)
} }
BMenuFrame::~BMenuFrame()
{
}
void void
BMenuFrame::AttachedToWindow() BMenuFrame::AttachedToWindow()
{ {
@@ -246,6 +218,7 @@ BMenuFrame::Draw(BRect updateRect)
} }
// #pragma mark - // #pragma mark -
@@ -253,8 +226,10 @@ BMenuWindow::BMenuWindow(const char *name)
// The window will be resized by BMenu, so just pass a dummy rect // The window will be resized by BMenu, so just pass a dummy rect
: BWindow(BRect(0, 0, 0, 0), name, B_BORDERED_WINDOW_LOOK, kMenuWindowFeel, : BWindow(BRect(0, 0, 0, 0), name, B_BORDERED_WINDOW_LOOK, kMenuWindowFeel,
B_NOT_ZOOMABLE | B_AVOID_FOCUS), B_NOT_ZOOMABLE | B_AVOID_FOCUS),
fScroller(NULL), fMenu(NULL),
fMenuFrame(NULL) fMenuFrame(NULL),
fUpperScroller(NULL),
fLowerScroller(NULL)
{ {
} }
@@ -273,6 +248,7 @@ BMenuWindow::AttachMenu(BMenu *menu)
fMenuFrame = new BMenuFrame(menu); fMenuFrame = new BMenuFrame(menu);
AddChild(fMenuFrame); AddChild(fMenuFrame);
menu->MakeFocus(true); menu->MakeFocus(true);
fMenu = menu;
} }
} }
@@ -280,14 +256,12 @@ BMenuWindow::AttachMenu(BMenu *menu)
void void
BMenuWindow::DetachMenu() BMenuWindow::DetachMenu()
{ {
DetachScrollers();
if (fMenuFrame) { if (fMenuFrame) {
if (fScroller) { RemoveChild(fMenuFrame);
DetachScrollers();
} else {
RemoveChild(fMenuFrame);
}
delete fMenuFrame; delete fMenuFrame;
fMenuFrame = NULL; fMenuFrame = NULL;
fMenu = NULL;
} }
} }
@@ -297,45 +271,112 @@ BMenuWindow::AttachScrollers()
{ {
// We want to attach a scroller only if there's a menu frame already // We want to attach a scroller only if there's a menu frame already
// existing. // existing.
if (fScroller || !fMenuFrame) if (!fMenu || !fMenuFrame)
return; return;
RemoveChild(fMenuFrame); fMenu->MakeFocus(true);
fScroller = new BMenuScroller(Bounds(), fMenuFrame->fMenu);
fScroller->AddChild(fMenuFrame);
AddChild(fScroller);
fMenuFrame->fMenu->MakeFocus(true); BRect frame = Bounds();
fUpperScroller = new UpperScroller(BRect(0, 0, frame.right, kScrollerHeight));
AddChild(fUpperScroller);
fLowerScroller = new LowerScroller(BRect(0, frame.bottom - kScrollerHeight, frame.right, frame.bottom));
AddChild(fLowerScroller);
fUpperScroller->SetEnabled(false);
fLowerScroller->SetEnabled(true);
fMenuFrame->ResizeBy(0, -2 * kScrollerHeight); fMenuFrame->ResizeBy(0, -2 * kScrollerHeight);
fMenuFrame->MoveBy(0, kScrollerHeight); fMenuFrame->MoveBy(0, kScrollerHeight);
fMenuFrame->Bounds().PrintToStream();
fValue = 0;
fLimit = fMenu->Bounds().Height() - (frame.Height() - 2 * kScrollerHeight);
} }
void void
BMenuWindow::DetachScrollers() BMenuWindow::DetachScrollers()
{ {
if(!fScroller || !fMenuFrame)
return;
// BeOS doesn't remember the position where the last scrolling ended, // BeOS doesn't remember the position where the last scrolling ended,
// so we just scroll back to the beginning. // so we just scroll back to the beginning.
fMenuFrame->fMenu->ScrollTo(0, 0); fMenu->ScrollTo(0, 0);
fScroller->RemoveChild(fMenuFrame); if (fLowerScroller) {
RemoveChild(fScroller); RemoveChild(fLowerScroller);
delete fLowerScroller;
fLowerScroller = NULL;
}
delete fScroller; if (fUpperScroller) {
fScroller = NULL; RemoveChild(fUpperScroller);
delete fUpperScroller;
fUpperScroller = NULL;
}
} }
bool bool
BMenuWindow::CheckForScrolling(BPoint cursor) BMenuWindow::CheckForScrolling(BPoint cursor)
{ {
if (!fScroller) if (!fMenuFrame)
return false; return false;
return fScroller->Scroll(cursor); return _Scroll(cursor);
}
bool
BMenuWindow::_Scroll(BPoint cursor)
{
ConvertFromScreen(&cursor);
BRect lowerFrame;
BRect upperFrame;
if (fLowerScroller)
lowerFrame = fLowerScroller->Frame();
if (fUpperScroller)
upperFrame = fUpperScroller->Frame();
if (fLowerScroller && fLowerScroller->IsEnabled() && lowerFrame.Contains(cursor)) {
if (fValue == 0) {
fUpperScroller->SetEnabled(true);
fUpperScroller->Invalidate();
}
if (fValue + kScrollStep >= fLimit) {
// If we reached the limit, we don't want to scroll a whole
// 'step' if not needed.
fMenu->ScrollBy(0, fLimit - fValue);
fValue = fLimit;
fLowerScroller->SetEnabled(false);
fLowerScroller->Invalidate();
} else {
fMenu->ScrollBy(0, kScrollStep);
fValue += kScrollStep;
}
} else if (fUpperScroller && fUpperScroller->IsEnabled() && upperFrame.Contains(cursor)) {
if (fValue == fLimit) {
fLowerScroller->SetEnabled(true);
fLowerScroller->Invalidate();
}
if (fValue - kScrollStep <= 0) {
fMenu->ScrollBy(0, -fValue);
fValue = 0;
fUpperScroller->SetEnabled(false);
fUpperScroller->Invalidate();
} else {
fMenu->ScrollBy(0, -kScrollStep);
fValue -= kScrollStep;
}
} else {
return false;
}
snooze(10000);
return true;
} }