Added a popup menu to the tabview: for now it only contains a "close

tab" item. Note that you can also close the tab by clicking on it with 
the tertiary mouse button. Renamed some methods of TermWindow.
I'm not really happy with this code (tab creation/deletion code is 
spread between TermWindow and SmartTabView), I will need to come up with 
something better.
There are still some visual glitches when tabs are switched, created or 
deleted.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21850 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stefano Ceccherini
2007-08-08 09:50:01 +00:00
parent 7f8d0be06f
commit d6f28abebe
4 changed files with 170 additions and 82 deletions
+87 -14
View File
@@ -8,11 +8,16 @@
#include "SmartTabView.h" #include "SmartTabView.h"
#include <MenuItem.h>
#include <Message.h> #include <Message.h>
#include <Messenger.h>
#include <PopUpMenu.h>
#include <Window.h> #include <Window.h>
#include <stdio.h> #include <stdio.h>
const static uint32 kCloseTab = 'ClTb';
SmartTabView::SmartTabView(BRect frame, const char *name, button_width width, SmartTabView::SmartTabView(BRect frame, const char *name, button_width width,
uint32 resizingMode, uint32 flags) uint32 resizingMode, uint32 flags)
: :
@@ -32,24 +37,45 @@ SmartTabView::~SmartTabView()
void void
SmartTabView::MouseDown(BPoint point) SmartTabView::MouseDown(BPoint point)
{ {
int32 buttons; bool handled = false;
Window()->CurrentMessage()->FindInt32("buttons", &buttons);
if (CountTabs() > 1 && point.y <= TabHeight() && buttons & B_TERTIARY_MOUSE_BUTTON) { if (CountTabs() > 1) {
for (int32 i = 0; i < CountTabs(); i++) { int32 tabIndex = _ClickedTabIndex(point);
if (TabFrame(i).Contains(point)) { if (tabIndex >= 0) {
// Select another tab int32 buttons;
if (i > 0) Window()->CurrentMessage()->FindInt32("buttons", &buttons);
Select(i - 1); if (buttons & B_SECONDARY_MOUSE_BUTTON) {
else if (i < CountTabs()) BMessage *message = new BMessage(kCloseTab);
Select(i + 1); message->AddInt32("index", tabIndex);
BTab *tab = RemoveTab(i);
delete tab; BPopUpMenu *popUpMenu = new BPopUpMenu("tab menu");
return; popUpMenu->AddItem(new BMenuItem("Close Tab", message));
popUpMenu->SetAsyncAutoDestruct(true);
popUpMenu->SetTargetForItems(BMessenger(this));
// TODO: I thought I'd get a "sticky" menu with this call...
// Bug in our implementation or I just have to use the "other"
// Go() method?
popUpMenu->Go(ConvertToScreen(point), true, true, true);
handled = true;
} else if (buttons & B_TERTIARY_MOUSE_BUTTON) {
RemoveAndDeleteTab(tabIndex);
handled = true;
} }
} }
} else }
if (!handled)
BTabView::MouseDown(point); BTabView::MouseDown(point);
}
void
SmartTabView::AttachedToWindow()
{
BTabView::AttachedToWindow();
} }
@@ -60,6 +86,24 @@ SmartTabView::AllAttached()
} }
void
SmartTabView::MessageReceived(BMessage *message)
{
switch (message->what) {
case kCloseTab:
{
int32 tabIndex = 0;
if (message->FindInt32("index", &tabIndex) == B_OK)
RemoveAndDeleteTab(tabIndex);
break;
}
default:
BTabView::MessageReceived(message);
break;
}
}
void void
SmartTabView::Select(int32 index) SmartTabView::Select(int32 index)
{ {
@@ -71,6 +115,21 @@ SmartTabView::Select(int32 index)
} }
void
SmartTabView::RemoveAndDeleteTab(int32 index)
{
// Select another tab
if (index == Selection()) {
if (index > 0)
Select(index - 1);
else if (index < CountTabs())
Select(index + 1);
}
BTab *tab = RemoveTab(index);
delete tab;
}
void void
SmartTabView::AddTab(BView *target, BTab *tab) SmartTabView::AddTab(BView *target, BTab *tab)
{ {
@@ -108,3 +167,17 @@ SmartTabView::DrawTabs()
} }
int32
SmartTabView::_ClickedTabIndex(const BPoint &point)
{
if (point.y <= TabHeight()) {
for (int32 i = 0; i < CountTabs(); i++) {
if (TabFrame(i).Contains(point))
return i;
}
}
return -1;
}
+10
View File
@@ -10,6 +10,7 @@
#include <TabView.h> #include <TabView.h>
class BPopUpMenu;
class SmartTabView : public BTabView { class SmartTabView : public BTabView {
public: public:
SmartTabView(BRect frame, const char *name, SmartTabView(BRect frame, const char *name,
@@ -22,13 +23,22 @@ public:
virtual void MouseDown(BPoint where); virtual void MouseDown(BPoint where);
virtual void AttachedToWindow();
virtual void AllAttached(); virtual void AllAttached();
virtual void MessageReceived(BMessage *message);
virtual void Select(int32 tab); virtual void Select(int32 tab);
void RemoveAndDeleteTab(int32 index);
virtual void AddTab(BView *target, BTab *tab = NULL); virtual void AddTab(BView *target, BTab *tab = NULL);
virtual BTab* RemoveTab(int32 index); virtual BTab* RemoveTab(int32 index);
virtual BRect DrawTabs(); virtual BRect DrawTabs();
private:
int32 _ClickedTabIndex(const BPoint &point);
}; };
#endif // __SMARTTABVIEW_H #endif // __SMARTTABVIEW_H
+70 -66
View File
@@ -116,7 +116,7 @@ TermWindow::_InitWindow(const char *command)
fTabView = new SmartTabView(textFrame, "tab view"); fTabView = new SmartTabView(textFrame, "tab view");
AddChild(fTabView); AddChild(fTabView);
_NewTab(command); _AddTab(command);
} }
@@ -202,8 +202,7 @@ TermWindow::_SetupMenu()
void void
TermWindow::MessageReceived(BMessage *message) TermWindow::MessageReceived(BMessage *message)
{ {
int32 coding_id; int32 encodingId;
BRect r;
BFont halfFont; BFont halfFont;
BFont fullFont; BFont fullFont;
bool findresult; bool findresult;
@@ -225,28 +224,24 @@ TermWindow::MessageReceived(BMessage *message)
_ActiveTermView()->Clear(); _ActiveTermView()->Clear();
break; break;
case MENU_SWITCH_TERM: { case MENU_SWITCH_TERM:
be_app->PostMessage(MENU_SWITCH_TERM); be_app->PostMessage(MENU_SWITCH_TERM);
break; break;
}
case kNewTab: case kNewTab:
_NewTab(NULL); _AddTab(NULL);
break; break;
case kCloseView: case kCloseView:
{
// TODO: We assume that this message was sent from the current active tab. // TODO: We assume that this message was sent from the current active tab.
// Since the implementation of BTabView uses AddChild/RemoveChild on the // Since the implementation of BTabView uses AddChild/RemoveChild on the
// views, the current active tab is the only one who is attached, thus // views, the current active tab is the only one who is attached, thus
// the only one which could send a message. // the only one which could send a message. Change this.
if (fTabView->CountTabs() > 1) _RemoveTab(fTabView->Selection());
delete fTabView->RemoveTab(fTabView->Selection());
else
PostMessage(B_QUIT_REQUESTED);
break; break;
}
case MENU_NEW_TERM: { case MENU_NEW_TERM:
{
app_info info; app_info info;
be_app->GetAppInfo(&info); be_app->GetAppInfo(&info);
@@ -255,18 +250,18 @@ TermWindow::MessageReceived(BMessage *message)
be_roster->Launch(TERM_SIGNATURE); be_roster->Launch(TERM_SIGNATURE);
break; break;
} }
case MENU_PREF_OPEN: { case MENU_PREF_OPEN:
if (!fPrefWindow) if (!fPrefWindow)
fPrefWindow = new PrefWindow(this); fPrefWindow = new PrefWindow(this);
else else
fPrefWindow->Activate(); fPrefWindow->Activate();
break; break;
}
case MSG_PREF_CLOSED: { case MSG_PREF_CLOSED:
fPrefWindow = NULL; fPrefWindow = NULL;
break; break;
}
case MENU_FIND_STRING: { case MENU_FIND_STRING:
if (!fFindPanel) { if (!fFindPanel) {
BRect r = Frame(); BRect r = Frame();
r.left += 20; r.left += 20;
@@ -278,8 +273,8 @@ TermWindow::MessageReceived(BMessage *message)
else else
fFindPanel->Activate(); fFindPanel->Activate();
break; break;
}
case MSG_FIND: { case MSG_FIND:
fFindPanel->PostMessage(B_QUIT_REQUESTED); fFindPanel->PostMessage(B_QUIT_REQUESTED);
message->FindBool("findselection", &fFindSelection); message->FindBool("findselection", &fFindSelection);
if (!fFindSelection) if (!fFindSelection)
@@ -314,8 +309,8 @@ TermWindow::MessageReceived(BMessage *message)
fFindBackwardMenuItem->SetEnabled(true); fFindBackwardMenuItem->SetEnabled(true);
fFindForwardMenuItem->SetEnabled(true); fFindForwardMenuItem->SetEnabled(true);
break; break;
}
case MENU_FIND_FORWARD: { case MENU_FIND_FORWARD:
findresult = _ActiveTermView()->Find(fFindString, true, fMatchCase, fMatchWord); findresult = _ActiveTermView()->Find(fFindString, true, fMatchCase, fMatchWord);
if (!findresult) { if (!findresult) {
BAlert *alert = new BAlert("find failed", "Not Found.", "Okay", NULL, BAlert *alert = new BAlert("find failed", "Not Found.", "Okay", NULL,
@@ -323,8 +318,8 @@ TermWindow::MessageReceived(BMessage *message)
alert->Go(); alert->Go();
} }
break; break;
}
case MENU_FIND_BACKWARD: { case MENU_FIND_BACKWARD:
findresult = _ActiveTermView()->Find(fFindString, false, fMatchCase, fMatchWord); findresult = _ActiveTermView()->Find(fFindString, false, fMatchCase, fMatchWord);
if (!findresult) { if (!findresult) {
BAlert *alert = new BAlert("find failed", "Not Found.", "Okay", NULL, BAlert *alert = new BAlert("find failed", "Not Found.", "Okay", NULL,
@@ -332,25 +327,25 @@ TermWindow::MessageReceived(BMessage *message)
alert->Go(); alert->Go();
} }
break; break;
}
case MSG_FIND_CLOSED: case MSG_FIND_CLOSED:
fFindPanel = NULL; fFindPanel = NULL;
break; break;
case MENU_ENCODING: { case MENU_ENCODING:
message->FindInt32 ("op", &coding_id); if (message->FindInt32("op", &encodingId) == B_OK)
_ActiveTermView()->SetEncoding(coding_id); _ActiveTermView()->SetEncoding(encodingId);
break; break;
}
// Message from Preference panel. // Message from Preference panel.
case MSG_ROWS_CHANGED: case MSG_ROWS_CHANGED:
case MSG_COLS_CHANGED: { case MSG_COLS_CHANGED:
r = _ActiveTermView()->SetTermSize (PrefHandler::Default()->getInt32 (PREF_ROWS), {
BRect rect = _ActiveTermView()->SetTermSize(PrefHandler::Default()->getInt32 (PREF_ROWS),
PrefHandler::Default()->getInt32 (PREF_COLS), 0); PrefHandler::Default()->getInt32 (PREF_COLS), 0);
ResizeTo (r.Width()+ B_V_SCROLL_BAR_WIDTH + kViewOffset * 2, ResizeTo (rect.Width()+ B_V_SCROLL_BAR_WIDTH + kViewOffset * 2,
r.Height()+fMenubar->Bounds().Height() + kViewOffset *2); rect.Height()+fMenubar->Bounds().Height() + kViewOffset *2);
BPath path; BPath path;
if (PrefHandler::GetDefaultPath(path) == B_OK) if (PrefHandler::GetDefaultPath(path) == B_OK)
@@ -360,7 +355,8 @@ TermWindow::MessageReceived(BMessage *message)
case MSG_HALF_FONT_CHANGED: case MSG_HALF_FONT_CHANGED:
case MSG_FULL_FONT_CHANGED: case MSG_FULL_FONT_CHANGED:
case MSG_HALF_SIZE_CHANGED: case MSG_HALF_SIZE_CHANGED:
case MSG_FULL_SIZE_CHANGED: { case MSG_FULL_SIZE_CHANGED:
{
halfFont.SetFamilyAndStyle (PrefHandler::Default()->getString(PREF_HALF_FONT_FAMILY),NULL); halfFont.SetFamilyAndStyle (PrefHandler::Default()->getString(PREF_HALF_FONT_FAMILY),NULL);
halfFont.SetSize (PrefHandler::Default()->getFloat(PREF_HALF_FONT_SIZE)); halfFont.SetSize (PrefHandler::Default()->getFloat(PREF_HALF_FONT_SIZE));
@@ -371,52 +367,51 @@ TermWindow::MessageReceived(BMessage *message)
fullFont.SetSpacing (B_FIXED_SPACING); fullFont.SetSpacing (B_FIXED_SPACING);
_ActiveTermView()->SetTermFont (&halfFont, &fullFont); _ActiveTermView()->SetTermFont (&halfFont, &fullFont);
r = _ActiveTermView()->SetTermSize (0, 0, 0); BRect rect = _ActiveTermView()->SetTermSize (0, 0, 0);
int width, height; int width, height;
_ActiveTermView()->GetFontSize(&width, &height);
_ActiveTermView()->GetFontSize (&width, &height);
SetSizeLimits (MIN_COLS * width, MAX_COLS * width, SetSizeLimits (MIN_COLS * width, MAX_COLS * width,
MIN_COLS * height, MAX_COLS * height); MIN_COLS * height, MAX_COLS * height);
ResizeTo (r.Width()+ B_V_SCROLL_BAR_WIDTH + kViewOffset * 2, ResizeTo(rect.Width()+ B_V_SCROLL_BAR_WIDTH + kViewOffset * 2,
r.Height()+fMenubar->Bounds().Height() + kViewOffset * 2); rect.Height()+fMenubar->Bounds().Height() + kViewOffset * 2);
_ActiveTermView()->Invalidate(); _ActiveTermView()->Invalidate();
break; break;
} }
case EIGHTYTWENTYFOUR: { case EIGHTYTWENTYFOUR:
PrefHandler::Default()->setString(PREF_COLS, "80"); PrefHandler::Default()->setString(PREF_COLS, "80");
PrefHandler::Default()->setString(PREF_ROWS, "24"); PrefHandler::Default()->setString(PREF_ROWS, "24");
PostMessage (MSG_COLS_CHANGED); PostMessage (MSG_COLS_CHANGED);
break; break;
}
case EIGHTYTWENTYFIVE: { case EIGHTYTWENTYFIVE:
PrefHandler::Default()->setString(PREF_COLS, "80"); PrefHandler::Default()->setString(PREF_COLS, "80");
PrefHandler::Default()->setString(PREF_ROWS, "25"); PrefHandler::Default()->setString(PREF_ROWS, "25");
PostMessage (MSG_COLS_CHANGED); PostMessage (MSG_COLS_CHANGED);
break; break;
}
case EIGHTYFORTY: { case EIGHTYFORTY:
PrefHandler::Default()->setString(PREF_COLS, "80"); PrefHandler::Default()->setString(PREF_COLS, "80");
PrefHandler::Default()->setString(PREF_ROWS, "40"); PrefHandler::Default()->setString(PREF_ROWS, "40");
PostMessage (MSG_COLS_CHANGED); PostMessage (MSG_COLS_CHANGED);
break; break;
}
case ONETHREETWOTWENTYFOUR: { case ONETHREETWOTWENTYFOUR:
PrefHandler::Default()->setString(PREF_COLS, "132"); PrefHandler::Default()->setString(PREF_COLS, "132");
PrefHandler::Default()->setString(PREF_ROWS, "24"); PrefHandler::Default()->setString(PREF_ROWS, "24");
PostMessage (MSG_COLS_CHANGED); PostMessage (MSG_COLS_CHANGED);
break; break;
}
case ONETHREETWOTWENTYFIVE: { case ONETHREETWOTWENTYFIVE:
PrefHandler::Default()->setString(PREF_COLS, "132"); PrefHandler::Default()->setString(PREF_COLS, "132");
PrefHandler::Default()->setString(PREF_ROWS, "25"); PrefHandler::Default()->setString(PREF_ROWS, "25");
PostMessage (MSG_COLS_CHANGED); PostMessage (MSG_COLS_CHANGED);
break; break;
}
case FULLSCREEN: { case FULLSCREEN:
if (!fSavedFrame.IsValid()) { // go fullscreen if (!fSavedFrame.IsValid()) { // go fullscreen
float mbHeight = fMenubar->Bounds().Height() + 1; float mbHeight = fMenubar->Bounds().Height() + 1;
fSavedFrame = Frame(); fSavedFrame = Frame();
@@ -440,39 +435,38 @@ TermWindow::MessageReceived(BMessage *message)
fSavedFrame = BRect(0,0,-1,-1); fSavedFrame = BRect(0,0,-1,-1);
} }
break; break;
}
case MSG_FONT_CHANGED: { case MSG_FONT_CHANGED:
PostMessage(MSG_HALF_FONT_CHANGED); PostMessage(MSG_HALF_FONT_CHANGED);
break; break;
}
case MSG_COLOR_CHANGED: { case MSG_COLOR_CHANGED:
_SetTermColors(); _SetTermColors();
_ActiveTermView()->Invalidate(); _ActiveTermView()->Invalidate();
break; break;
}
case SAVE_AS_DEFAULT: { case SAVE_AS_DEFAULT:
{
BPath path; BPath path;
if (PrefHandler::GetDefaultPath(path) == B_OK) if (PrefHandler::GetDefaultPath(path) == B_OK)
PrefHandler::Default()->SaveAsText(path.Path(), PREFFILE_MIMETYPE); PrefHandler::Default()->SaveAsText(path.Path(), PREFFILE_MIMETYPE);
break; break;
} }
case MENU_PAGE_SETUP: { case MENU_PAGE_SETUP:
_DoPageSetup(); _DoPageSetup();
break; break;
}
case MENU_PRINT: { case MENU_PRINT:
_DoPrint(); _DoPrint();
break; break;
}
case B_ABOUT_REQUESTED: { case B_ABOUT_REQUESTED:
be_app->PostMessage(B_ABOUT_REQUESTED); be_app->PostMessage(B_ABOUT_REQUESTED);
break; break;
}
default: { default:
BWindow::MessageReceived(message); BWindow::MessageReceived(message);
break; break;
}
} }
} }
@@ -567,7 +561,7 @@ TermWindow::_DoPrint()
void void
TermWindow::_NewTab(const char *command) TermWindow::_AddTab(const char *command)
{ {
// Setup font. // Setup font.
@@ -628,6 +622,16 @@ TermWindow::_NewTab(const char *command)
} }
void
TermWindow::_RemoveTab(int32 index)
{
if (fTabView->CountTabs() > 1)
delete fTabView->RemoveTab(fTabView->Selection());
else
PostMessage(B_QUIT_REQUESTED);
}
TermView * TermView *
TermWindow::_ActiveTermView() TermWindow::_ActiveTermView()
{ {
+2 -1
View File
@@ -59,7 +59,8 @@ private:
void _SetupMenu(); void _SetupMenu();
status_t _DoPageSetup(); status_t _DoPageSetup();
void _DoPrint(); void _DoPrint();
void _NewTab(const char *command); void _AddTab(const char *command);
void _RemoveTab(int32 index);
TermView* _ActiveTermView(); TermView* _ActiveTermView();
SmartTabView *fTabView; SmartTabView *fTabView;