* BMenu now scrolls when you press page up/down, if possible.

* BMenuWindow no longer uses a fixed scroll step - instead, the menu sets it
  to the height of its first item.
* Cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31389 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2009-07-03 12:09:16 +00:00
parent 9515252e02
commit 4e23bc0383
3 changed files with 136 additions and 80 deletions
+33 -28
View File
@@ -1,13 +1,13 @@
/* /*
* Copyright 2001-2006, Haiku, Inc. * Copyright 2001-2009, Haiku, Inc.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
* Marc Flerackers ([email protected]) * Marc Flerackers ([email protected])
* Stefano Ceccherini ([email protected]) * Stefano Ceccherini ([email protected])
*/ */
#ifndef __MENUWINDOW_H #ifndef MENU_WINDOW_H
#define __MENUWINDOW_H #define MENU_WINDOW_H
#include <Window.h> #include <Window.h>
@@ -22,34 +22,39 @@ class BMenuScroller;
class BMenuWindow : public BWindow { class BMenuWindow : public BWindow {
public: public:
BMenuWindow(const char *name); BMenuWindow(const char* name);
virtual ~BMenuWindow(); virtual ~BMenuWindow();
virtual void DispatchMessage(BMessage *message, BHandler *handler); virtual void DispatchMessage(BMessage* message,
BHandler* handler);
void AttachMenu(BMenu *menu);
void DetachMenu();
void AttachScrollers();
void DetachScrollers();
bool CheckForScrolling(const BPoint &cursor); void AttachMenu(BMenu* menu);
bool TryScrollBy(const float &step); void DetachMenu();
private: void AttachScrollers();
BMenu *fMenu; void DetachScrollers();
BMenuFrame *fMenuFrame;
BMenuScroller *fUpperScroller; void SetSmallStep(float step);
BMenuScroller *fLowerScroller; void GetSteps(float* _smallStep, float* _largeStep);
bool HasScrollers() const;
float fValue; bool CheckForScrolling(const BPoint& cursor);
float fLimit; bool TryScrollBy(const float& step);
bool _Scroll(const BPoint &cursor); private:
void _ScrollBy(const float &step); bool _Scroll(const BPoint& cursor);
void _ScrollBy(const float& step);
BMenu* fMenu;
BMenuFrame* fMenuFrame;
BMenuScroller* fUpperScroller;
BMenuScroller* fLowerScroller;
float fScrollStep;
float fValue;
float fLimit;
}; };
} // namespace BPrivate } // namespace BPrivate
#endif // __MENUWINDOW_H #endif // MENU_WINDOW_H
+33 -9
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2008, Haiku, Inc. * Copyright 2001-2009, Haiku, Inc.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -8,6 +8,8 @@
* Rene Gollent ([email protected]) * Rene Gollent ([email protected])
*/ */
#include <Menu.h>
#include <new> #include <new>
#include <ctype.h> #include <ctype.h>
#include <string.h> #include <string.h>
@@ -18,13 +20,13 @@
#include <FindDirectory.h> #include <FindDirectory.h>
#include <Layout.h> #include <Layout.h>
#include <LayoutUtils.h> #include <LayoutUtils.h>
#include <Menu.h>
#include <MenuBar.h> #include <MenuBar.h>
#include <MenuItem.h> #include <MenuItem.h>
#include <Messenger.h> #include <Messenger.h>
#include <Path.h> #include <Path.h>
#include <PropertyInfo.h> #include <PropertyInfo.h>
#include <Screen.h> #include <Screen.h>
#include <ScrollBar.h>
#include <Window.h> #include <Window.h>
#include <AppServerLink.h> #include <AppServerLink.h>
@@ -819,9 +821,7 @@ BMenu::MessageReceived(BMessage *msg)
switch (msg->what) { switch (msg->what) {
case B_MOUSE_WHEEL_CHANGED: case B_MOUSE_WHEEL_CHANGED:
{ {
//float deltaX = 0
float deltaY = 0; float deltaY = 0;
//msg->FindFloat("be:wheel_delta_x", &deltaX);
msg->FindFloat("be:wheel_delta_y", &deltaY); msg->FindFloat("be:wheel_delta_y", &deltaY);
if (deltaY == 0) if (deltaY == 0)
return; return;
@@ -830,7 +830,9 @@ BMenu::MessageReceived(BMessage *msg)
if (window == NULL) if (window == NULL)
return; return;
window->TryScrollBy(deltaY); float smallStep;
window->GetSteps(&smallStep, NULL);
window->TryScrollBy(deltaY * smallStep);
break; break;
} }
default: default:
@@ -890,6 +892,21 @@ BMenu::KeyDown(const char *bytes, int32 numBytes)
} }
break; break;
case B_PAGE_UP:
case B_PAGE_DOWN:
{
BMenuWindow *window = dynamic_cast<BMenuWindow *>(Window());
if (window == NULL || !window->HasScrollers())
break;
int32 deltaY = bytes[0] == B_PAGE_UP ? -1 : 1;
float largeStep;
window->GetSteps(NULL, &largeStep);
window->TryScrollBy(deltaY * largeStep);
break;
}
case B_ENTER: case B_ENTER:
case B_SPACE: case B_SPACE:
if (fSelected) { if (fSelected) {
@@ -1426,6 +1443,13 @@ BMenu::_Show(bool selectFirstItem)
fAttachAborted = false; fAttachAborted = false;
window->AttachMenu(this); window->AttachMenu(this);
if (ItemAt(0) != NULL) {
float width, height;
ItemAt(0)->GetContentSize(&width, &height);
window->SetSmallStep(ceilf(height));
}
// Menu didn't have the time to add its items: aborting... // Menu didn't have the time to add its items: aborting...
if (fAttachAborted) { if (fAttachAborted) {
window->DetachMenu(); window->DetachMenu();
@@ -2213,7 +2237,7 @@ BMenu::_CalcFrame(BPoint where, bool *scrollOn)
if (frame.right > screenFrame.right) if (frame.right > screenFrame.right)
frame.OffsetBy(screenFrame.right - frame.right, 0); frame.OffsetBy(screenFrame.right - frame.right, 0);
} }
if (!scroll) { if (!scroll) {
// basically, if this returns false, it means // basically, if this returns false, it means
// that the menu frame won't fit completely inside the screen // that the menu frame won't fit completely inside the screen
@@ -2221,10 +2245,10 @@ BMenu::_CalcFrame(BPoint where, bool *scrollOn)
// not left/right // not left/right
scroll = screenFrame.Height() < frame.Height(); scroll = screenFrame.Height() < frame.Height();
} }
if (scrollOn != NULL) if (scrollOn != NULL)
*scrollOn = scroll; *scrollOn = scroll;
return frame; return frame;
} }
@@ -2286,7 +2310,7 @@ BMenu::_InvokeItem(BMenuItem *item, bool now)
rootMenu = parent; rootMenu = parent;
parent = rootMenu->Supermenu(); parent = rootMenu->Supermenu();
} while (parent != NULL); } while (parent != NULL);
if (rootMenu->LockLooper()) { if (rootMenu->LockLooper()) {
item->Invoke(); item->Invoke();
rootMenu->UnlockLooper(); rootMenu->UnlockLooper();
+70 -43
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2007, Haiku, Inc. * Copyright 2001-2009, Haiku, Inc.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -14,6 +14,8 @@
#include <ControlLook.h> #include <ControlLook.h>
#include <Debug.h> #include <Debug.h>
#include <Menu.h> #include <Menu.h>
#include <MenuItem.h>
#include <MenuPrivate.h> #include <MenuPrivate.h>
#include <WindowPrivate.h> #include <WindowPrivate.h>
@@ -23,7 +25,7 @@ namespace BPrivate {
class BMenuScroller : public BView { class BMenuScroller : public BView {
public: public:
BMenuScroller(BRect frame); BMenuScroller(BRect frame);
bool IsEnabled() const; bool IsEnabled() const;
void SetEnabled(const bool &enabled); void SetEnabled(const bool &enabled);
private: private:
@@ -34,11 +36,11 @@ class BMenuScroller : public BView {
class BMenuFrame : public BView { class BMenuFrame : public BView {
public: public:
BMenuFrame(BMenu *menu); BMenuFrame(BMenu *menu);
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;
@@ -67,14 +69,13 @@ using namespace BPrivate;
const int kScrollerHeight = 10; const int kScrollerHeight = 10;
const int kScrollStep = 19;
BMenuScroller::BMenuScroller(BRect frame) 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),
fEnabled(false) fEnabled(false)
{ {
SetViewColor(ui_color(B_MENU_BACKGROUND_COLOR)); SetViewColor(ui_color(B_MENU_BACKGROUND_COLOR));
} }
@@ -112,11 +113,11 @@ UpperScroller::Draw(BRect updateRect)
if (IsEnabled()) if (IsEnabled())
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(Bounds(), 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));
@@ -137,7 +138,7 @@ void
LowerScroller::Draw(BRect updateRect) LowerScroller::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));
BRect frame = Bounds(); BRect frame = Bounds();
// Draw the lower arrow. // Draw the lower arrow.
if (IsEnabled()) if (IsEnabled())
@@ -164,16 +165,16 @@ BMenuFrame::BMenuFrame(BMenu *menu)
fMenu(menu) fMenu(menu)
{ {
} }
void void
BMenuFrame::AttachedToWindow() BMenuFrame::AttachedToWindow()
{ {
BView::AttachedToWindow(); BView::AttachedToWindow();
if (fMenu != NULL) if (fMenu != NULL)
AddChild(fMenu); AddChild(fMenu);
ResizeTo(Window()->Bounds().Width(), Window()->Bounds().Height()); ResizeTo(Window()->Bounds().Width(), Window()->Bounds().Height());
if (fMenu != NULL) { if (fMenu != NULL) {
BFont font; BFont font;
@@ -181,7 +182,7 @@ BMenuFrame::AttachedToWindow()
SetFont(&font); SetFont(&font);
} }
} }
void void
BMenuFrame::DetachedFromWindow() BMenuFrame::DetachedFromWindow()
@@ -240,10 +241,11 @@ 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),
fMenu(NULL), fMenu(NULL),
fMenuFrame(NULL), fMenuFrame(NULL),
fUpperScroller(NULL), fUpperScroller(NULL),
fLowerScroller(NULL) fLowerScroller(NULL),
fScrollStep(19)
{ {
SetSizeLimits(2, 10000, 2, 10000); SetSizeLimits(2, 10000, 2, 10000);
} }
@@ -279,7 +281,7 @@ BMenuWindow::AttachMenu(BMenu *menu)
void void
BMenuWindow::DetachMenu() BMenuWindow::DetachMenu()
{ {
DetachScrollers(); DetachScrollers();
if (fMenuFrame) { if (fMenuFrame) {
RemoveChild(fMenuFrame); RemoveChild(fMenuFrame);
delete fMenuFrame; delete fMenuFrame;
@@ -296,30 +298,30 @@ BMenuWindow::AttachScrollers()
// menu frame already existing. // menu frame already existing.
if (!fMenu || !fMenuFrame) if (!fMenu || !fMenuFrame)
return; return;
fMenu->MakeFocus(true); fMenu->MakeFocus(true);
BRect frame = Bounds(); BRect frame = Bounds();
if (fUpperScroller == NULL) { if (fUpperScroller == NULL) {
fUpperScroller = new UpperScroller( fUpperScroller = new UpperScroller(
BRect(0, 0, frame.right, kScrollerHeight - 1)); BRect(0, 0, frame.right, kScrollerHeight - 1));
AddChild(fUpperScroller); AddChild(fUpperScroller);
} }
if (fLowerScroller == NULL) { if (fLowerScroller == NULL) {
fLowerScroller = new LowerScroller( fLowerScroller = new LowerScroller(
BRect(0, frame.bottom - kScrollerHeight + 1, frame.right, BRect(0, frame.bottom - kScrollerHeight + 1, frame.right,
frame.bottom)); frame.bottom));
AddChild(fLowerScroller); AddChild(fLowerScroller);
} }
fUpperScroller->SetEnabled(false); fUpperScroller->SetEnabled(false);
fLowerScroller->SetEnabled(true); fLowerScroller->SetEnabled(true);
fMenuFrame->ResizeBy(0, -2 * kScrollerHeight); fMenuFrame->ResizeBy(0, -2 * kScrollerHeight);
fMenuFrame->MoveBy(0, kScrollerHeight); fMenuFrame->MoveBy(0, kScrollerHeight);
fValue = 0; fValue = 0;
fLimit = fMenu->Bounds().Height() - (frame.Height() - 2 * kScrollerHeight); fLimit = fMenu->Bounds().Height() - (frame.Height() - 2 * kScrollerHeight);
} }
@@ -330,7 +332,7 @@ BMenuWindow::DetachScrollers()
{ {
// 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.
if (fMenu) if (fMenu)
fMenu->ScrollTo(0, 0); fMenu->ScrollTo(0, 0);
if (fLowerScroller) { if (fLowerScroller) {
@@ -343,7 +345,36 @@ BMenuWindow::DetachScrollers()
RemoveChild(fUpperScroller); RemoveChild(fUpperScroller);
delete fUpperScroller; delete fUpperScroller;
fUpperScroller = NULL; fUpperScroller = NULL;
} }
}
void
BMenuWindow::SetSmallStep(float step)
{
fScrollStep = step;
}
void
BMenuWindow::GetSteps(float* _smallStep, float* _largeStep)
{
if (_smallStep != NULL)
*_smallStep = fScrollStep;
if (_largeStep != NULL) {
if (fMenuFrame != NULL)
*_largeStep = fMenuFrame->Bounds().Height() - fScrollStep;
else
*_largeStep = fScrollStep * 2;
}
}
bool
BMenuWindow::HasScrollers() const
{
return fMenuFrame != NULL && fUpperScroller != NULL
&& fLowerScroller != NULL;
} }
@@ -352,39 +383,38 @@ BMenuWindow::CheckForScrolling(const BPoint &cursor)
{ {
if (!fMenuFrame || !fUpperScroller || !fLowerScroller) if (!fMenuFrame || !fUpperScroller || !fLowerScroller)
return false; return false;
return _Scroll(cursor); return _Scroll(cursor);
} }
bool bool
BMenuWindow::TryScrollBy(const float &step) BMenuWindow::TryScrollBy(const float& step)
{ {
if (!fMenuFrame || !fUpperScroller || !fLowerScroller) if (!fMenuFrame || !fUpperScroller || !fLowerScroller)
return false; return false;
_ScrollBy(step); _ScrollBy(step);
return true; return true;
} }
bool bool
BMenuWindow::_Scroll(const BPoint &where) BMenuWindow::_Scroll(const BPoint& where)
{ {
ASSERT((fLowerScroller != NULL)); ASSERT((fLowerScroller != NULL));
ASSERT((fUpperScroller != NULL)); ASSERT((fUpperScroller != NULL));
const BPoint cursor = ConvertFromScreen(where); const BPoint cursor = ConvertFromScreen(where);
BRect lowerFrame = fLowerScroller->Frame(); BRect lowerFrame = fLowerScroller->Frame();
BRect upperFrame = fUpperScroller->Frame(); BRect upperFrame = fUpperScroller->Frame();
if (fLowerScroller->IsEnabled() && lowerFrame.Contains(cursor)) { if (fLowerScroller->IsEnabled() && lowerFrame.Contains(cursor))
_ScrollBy(1); _ScrollBy(1);
} else if (fUpperScroller->IsEnabled() && upperFrame.Contains(cursor)) { else if (fUpperScroller->IsEnabled() && upperFrame.Contains(cursor))
_ScrollBy(-1); _ScrollBy(-1);
} else else
return false; return false;
snooze(5000); snooze(5000);
@@ -394,7 +424,7 @@ BMenuWindow::_Scroll(const BPoint &where)
void void
BMenuWindow::_ScrollBy(const float &step) BMenuWindow::_ScrollBy(const float& step)
{ {
if (step > 0) { if (step > 0) {
if (fValue == 0) { if (fValue == 0) {
@@ -402,17 +432,15 @@ BMenuWindow::_ScrollBy(const float &step)
fUpperScroller->Invalidate(); fUpperScroller->Invalidate();
} }
if (fValue + kScrollStep >= fLimit) { if (fValue + step >= fLimit) {
// If we reached the limit, we don't want to scroll a whole // If we reached the limit, only scroll to the end
// 'step' if not needed.
fMenu->ScrollBy(0, fLimit - fValue); fMenu->ScrollBy(0, fLimit - fValue);
fValue = fLimit; fValue = fLimit;
fLowerScroller->SetEnabled(false); fLowerScroller->SetEnabled(false);
fLowerScroller->Invalidate(); fLowerScroller->Invalidate();
} else { } else {
fMenu->ScrollBy(0, kScrollStep); fMenu->ScrollBy(0, step);
fValue += kScrollStep; fValue += step;
} }
} else if (step < 0) { } else if (step < 0) {
if (fValue == fLimit) { if (fValue == fLimit) {
@@ -420,15 +448,14 @@ BMenuWindow::_ScrollBy(const float &step)
fLowerScroller->Invalidate(); fLowerScroller->Invalidate();
} }
if (fValue - kScrollStep <= 0) { if (fValue + step <= 0) {
fMenu->ScrollBy(0, -fValue); fMenu->ScrollBy(0, -fValue);
fValue = 0; fValue = 0;
fUpperScroller->SetEnabled(false); fUpperScroller->SetEnabled(false);
fUpperScroller->Invalidate(); fUpperScroller->Invalidate();
} else { } else {
fMenu->ScrollBy(0, -kScrollStep); fMenu->ScrollBy(0, step);
fValue -= kScrollStep; fValue += step;
} }
} }
} }