xref: /haiku/src/apps/terminal/SmartTabView.cpp (revision 4f2fd49bdc6078128b1391191e4edac647044c3d)
1 /*
2  * Copyright 2007, Haiku. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  *	Authors:
6  *		Stefano Ceccherini (burton666@libero.it)
7  */
8 
9 #include "SmartTabView.h"
10 
11 #include <MenuItem.h>
12 #include <Message.h>
13 #include <Messenger.h>
14 #include <PopUpMenu.h>
15 #include <Window.h>
16 
17 #include <stdio.h>
18 
19 const static uint32 kCloseTab = 'ClTb';
20 
21 SmartTabView::SmartTabView(BRect frame, const char *name, button_width width,
22 				uint32 resizingMode, uint32 flags)
23 	:
24 	BTabView(frame, name, width, resizingMode, flags),
25 	fInsets(0, 0, 0, 0)
26 {
27 	// Resize the container view to fill the complete tab view for single-tab
28 	// mode. Later, when more than one tab is added, we shrink the container
29 	// view again.
30 	frame.OffsetTo(B_ORIGIN);
31 	ContainerView()->MoveTo(frame.LeftTop());
32 	ContainerView()->ResizeTo(frame.Width(), frame.Height());
33 }
34 
35 
36 SmartTabView::~SmartTabView()
37 {
38 }
39 
40 
41 void
42 SmartTabView::SetInsets(float left, float top, float right, float bottom)
43 {
44 	fInsets.left = left;
45 	fInsets.top = top;
46 	fInsets.right = right;
47 	fInsets.bottom = bottom;
48 }
49 
50 
51 void
52 SmartTabView::MouseDown(BPoint point)
53 {
54 	bool handled = false;
55 
56 	if (CountTabs() > 1) {
57 		int32 tabIndex = _ClickedTabIndex(point);
58 		if (tabIndex >= 0) {
59 			int32 buttons;
60 			Window()->CurrentMessage()->FindInt32("buttons", &buttons);
61 			if (buttons & B_SECONDARY_MOUSE_BUTTON) {
62 				BMessage *message = new BMessage(kCloseTab);
63 				message->AddInt32("index", tabIndex);
64 
65 				BPopUpMenu *popUpMenu = new BPopUpMenu("tab menu");
66 				popUpMenu->AddItem(new BMenuItem("Close Tab", message));
67 				popUpMenu->SetAsyncAutoDestruct(true);
68 				popUpMenu->SetTargetForItems(BMessenger(this));
69 				popUpMenu->Go(ConvertToScreen(point), true, true, true);
70 
71 				handled = true;
72 			} else if (buttons & B_TERTIARY_MOUSE_BUTTON) {
73 				RemoveAndDeleteTab(tabIndex);
74 				handled = true;
75 			}
76 		}
77 	}
78 
79 	if (!handled)
80 		BTabView::MouseDown(point);
81 
82 }
83 
84 
85 void
86 SmartTabView::AttachedToWindow()
87 {
88 	BTabView::AttachedToWindow();
89 }
90 
91 
92 void
93 SmartTabView::AllAttached()
94 {
95 	BTabView::AllAttached();
96 }
97 
98 
99 void
100 SmartTabView::MessageReceived(BMessage *message)
101 {
102 	switch (message->what) {
103 		case kCloseTab:
104 		{
105 			int32 tabIndex = 0;
106 			if (message->FindInt32("index", &tabIndex) == B_OK)
107 				RemoveAndDeleteTab(tabIndex);
108 			break;
109 		}
110 		default:
111 			BTabView::MessageReceived(message);
112 			break;
113 	}
114 }
115 
116 
117 void
118 SmartTabView::Select(int32 index)
119 {
120 	BTabView::Select(index);
121 	BView *view = ViewForTab(index);
122 	if (view != NULL) {
123 		view->MoveTo(fInsets.LeftTop());
124 		view->ResizeTo(ContainerView()->Bounds().Width()
125 				- fInsets.left - fInsets.right,
126 			ContainerView()->Bounds().Height() - fInsets.top - fInsets.bottom);
127 	}
128 }
129 
130 
131 void
132 SmartTabView::RemoveAndDeleteTab(int32 index)
133 {
134 	// Select another tab
135 	if (index == Selection()) {
136 		if (index > 0)
137 			Select(index - 1);
138 		else if (index < CountTabs())
139 			Select(index + 1);
140 	}
141 	delete RemoveTab(index);
142 }
143 
144 
145 void
146 SmartTabView::AddTab(BView *target, BTab *tab)
147 {
148 	if (target == NULL)
149 		return;
150 
151 	BTabView::AddTab(target, tab);
152 
153 	if (CountTabs() == 1) {
154 		// Call select on the tab, since
155 		// we're resizing the contained view
156 		// inside that function
157 		Select(0);
158 	} else if (CountTabs() == 2) {
159 		// Need to resize the view, since we're
160 		// switching from "normal" to tabbed mode
161 		ContainerView()->ResizeBy(0, -TabHeight());
162 		ContainerView()->MoveBy(0, TabHeight());
163 		Window()->ResizeBy(0, TabHeight());
164 	}
165 
166 	Invalidate(TabFrame(CountTabs() - 1).InsetByCopy(-2, -2));
167 }
168 
169 
170 BTab *
171 SmartTabView::RemoveTab(int32 index)
172 {
173 	if (CountTabs() == 2) {
174 		// see above
175 		Window()->ResizeBy(0, -TabHeight());
176 		ContainerView()->MoveBy(0, -TabHeight());
177 		ContainerView()->ResizeBy(0, TabHeight());
178 	}
179 	return BTabView::RemoveTab(index);
180 }
181 
182 
183 BRect
184 SmartTabView::DrawTabs()
185 {
186 	if (CountTabs() > 1)
187 		return BTabView::DrawTabs();
188 	return BRect();
189 }
190 
191 
192 int32
193 SmartTabView::_ClickedTabIndex(const BPoint &point)
194 {
195 	if (point.y <= TabHeight()) {
196 		for (int32 i = 0; i < CountTabs(); i++) {
197 			if (TabFrame(i).Contains(point))
198 				return i;
199 		}
200 	}
201 
202 	return -1;
203 }
204