xref: /haiku/src/apps/stylededit/StatusView.cpp (revision 90ae2e54f6ccaca73c011a2aa4cdd660417108ad)
1 /*
2  * Copyright 2002-2012, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Vlad Slepukhin
7  *		Siarzhuk Zharski
8  */
9 
10 
11 #include "StatusView.h"
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 
17 #include <Catalog.h>
18 #include <CharacterSet.h>
19 #include <CharacterSetRoster.h>
20 #include <ControlLook.h>
21 #include <MenuItem.h>
22 #include <Message.h>
23 #include <PopUpMenu.h>
24 #include <ScrollView.h>
25 #include <StringView.h>
26 #include <Window.h>
27 
28 #include "Constants.h"
29 #include "StyledEditWindow.h"
30 
31 
32 const float kHorzSpacing = 5.f;
33 #define UTF8_EXPAND_ARROW "\xe2\x96\xbe"
34 
35 using namespace BPrivate;
36 
37 
38 #undef B_TRANSLATION_CONTEXT
39 #define B_TRANSLATION_CONTEXT "StatusView"
40 
41 
42 StatusView::StatusView(BScrollView* scrollView)
43 			:
44 			BView(BRect(), "statusview",
45 				B_FOLLOW_BOTTOM | B_FOLLOW_LEFT, B_WILL_DRAW),
46 			fScrollView(scrollView),
47 			fPreferredSize(0., 0.),
48 			fReadOnly(false)
49 {
50 	memset(fCellWidth, 0, sizeof(fCellWidth));
51 }
52 
53 
54 StatusView::~StatusView()
55 {
56 }
57 
58 
59 void
60 StatusView::AttachedToWindow()
61 {
62 	SetFont(be_plain_font);
63 	SetFontSize(10.);
64 
65 	BMessage message(UPDATE_STATUS);
66 	message.AddInt32("line", 1);
67 	message.AddInt32("column", 1);
68 	message.AddString("encoding", "");
69 	SetStatus(&message);
70 
71 	BScrollBar* scrollBar = fScrollView->ScrollBar(B_HORIZONTAL);
72 	MoveTo(0., scrollBar->Frame().top);
73 
74 	rgb_color color = B_TRANSPARENT_COLOR;
75 	BView* parent = Parent();
76 	if (parent != NULL)
77 		color = parent->ViewColor();
78 
79 	if (color == B_TRANSPARENT_COLOR)
80 		color = ui_color(B_PANEL_BACKGROUND_COLOR);
81 
82 	SetViewColor(color);
83 
84 	ResizeToPreferred();
85 }
86 
87 
88 void
89 StatusView::GetPreferredSize(float* _width, float* _height)
90 {
91 	_ValidatePreferredSize();
92 
93 	if (_width)
94 		*_width = fPreferredSize.width;
95 
96 	if (_height)
97 		*_height = fPreferredSize.height;
98 }
99 
100 
101 void
102 StatusView::ResizeToPreferred()
103 {
104 	float width, height;
105 	GetPreferredSize(&width, &height);
106 
107 	if (Bounds().Width() > width)
108 		width = Bounds().Width();
109 
110 	BView::ResizeTo(width, height);
111 }
112 
113 
114 void
115 StatusView::Draw(BRect updateRect)
116 {
117 	if (fPreferredSize.width <= 0)
118 		return;
119 
120 	if (be_control_look != NULL) {
121 		BRect bounds(Bounds());
122 		be_control_look->DrawMenuBarBackground(this,
123 			bounds, updateRect,	ViewColor());
124 	}
125 
126 	BRect bounds(Bounds());
127 	rgb_color highColor = HighColor();
128 	SetHighColor(tint_color(ViewColor(), B_DARKEN_2_TINT));
129 	StrokeLine(bounds.LeftTop(), bounds.RightTop());
130 
131 	float x = bounds.left;
132 	for (size_t i = 0; i < kStatusCellCount - 1; i++) {
133 		x += fCellWidth[i];
134 		StrokeLine(BPoint(x, bounds.top + 3), BPoint(x, bounds.bottom - 3));
135 	}
136 
137 	SetLowColor(ViewColor());
138 	SetHighColor(highColor);
139 
140 	font_height fontHeight;
141 	GetFontHeight(&fontHeight);
142 
143 	x = bounds.left;
144 	float y = (bounds.bottom + bounds.top
145 		+ ceilf(fontHeight.ascent) - ceilf(fontHeight.descent)) / 2;
146 
147 	for (size_t i = 0; i < kStatusCellCount; i++) {
148 		if (fCellText[i].Length() == 0)
149 			continue;
150 		DrawString(fCellText[i], BPoint(x + kHorzSpacing, y));
151 		x += fCellWidth[i];
152 	}
153 }
154 
155 
156 void
157 StatusView::MouseDown(BPoint where)
158 {
159 	if (!fReadOnly)
160 		return;
161 
162 	if (where.x < fCellWidth[kPositionCell])
163 		return;
164 
165 	int32 clicks = 0;
166 	BMessage* message = Window()->CurrentMessage();
167 	if (message != NULL
168 		&& message->FindInt32("clicks", &clicks) == B_OK && clicks > 1)
169 			return;
170 
171 	BPopUpMenu *menu = new BPopUpMenu(B_EMPTY_STRING, false, false);
172 	float left = fCellWidth[kPositionCell] + fCellWidth[kEncodingCell];
173 	if (where.x < left)
174 		StyledEditWindow::PopulateEncodingMenu(menu, fEncoding);
175 	else
176 		menu->AddItem(new BMenuItem(B_TRANSLATE("Unlock file"),
177 					new BMessage(UNLOCK_FILE)));
178 	where.x = left;
179 	where.y = Bounds().bottom;
180 
181 	ConvertToScreen(&where);
182 	menu->SetTargetForItems(this);
183 	menu->Go(where, true, true,	true);
184 }
185 
186 
187 void
188 StatusView::SetStatus(BMessage* message)
189 {
190 	int32 line = 0, column = 0;
191 	if (B_OK == message->FindInt32("line", &line)
192 		&& B_OK == message->FindInt32("column", &column))
193 	{
194 		char info[256];
195 		snprintf(info, sizeof(info),
196 				B_TRANSLATE("line %d, column %d"), line, column);
197 		fCellText[kPositionCell].SetTo(info);
198 	}
199 
200 	if (B_OK == message->FindString("encoding", &fEncoding)) {
201 		// sometime corresponding Int-32 "encoding" attrib is read as string :(
202 		if (fEncoding.Length() == 0
203 			|| fEncoding.Compare("\xff\xff") == 0
204 			|| fEncoding.Compare("UTF-8") == 0)
205 		{
206 			fCellText[kEncodingCell] = "UTF-8";
207 			fEncoding.Truncate(0);
208 		} else {
209 			const BCharacterSet* charset
210 				= BCharacterSetRoster::FindCharacterSetByName(fEncoding);
211 			fCellText[kEncodingCell]
212 				= charset != NULL ? charset->GetPrintName() : "";
213 		}
214 		fCellText[kEncodingCell] << " " UTF8_EXPAND_ARROW;
215 	}
216 
217 	bool modified = false;
218 	fReadOnly = false;
219 	if (B_OK == message->FindBool("modified", &modified) && modified) {
220 		fCellText[kFileStateCell] = B_TRANSLATE("Modified");
221 	} else if (B_OK == message->FindBool("readOnly", &fReadOnly) && fReadOnly) {
222 		fCellText[kFileStateCell] = B_TRANSLATE("Read-only");
223 		fCellText[kFileStateCell] << " " UTF8_EXPAND_ARROW;
224 	} else
225 		fCellText[kFileStateCell].Truncate(0);
226 
227 	_ValidatePreferredSize();
228 	Invalidate();
229 }
230 
231 
232 void
233 StatusView::_ValidatePreferredSize()
234 {
235 	float orgWidth = fPreferredSize.width;
236 	// width
237 	fPreferredSize.width = 0.f;
238 	for (size_t i = 0; i < kStatusCellCount; i++) {
239 		if (fCellText[i].Length() == 0) {
240 			fCellWidth[i] = 0;
241 			continue;
242 		}
243 		float width = ceilf(StringWidth(fCellText[i]));
244 		if (width > 0)
245 			width += kHorzSpacing * 2;
246 		if (width > fCellWidth[i] || i != kPositionCell)
247 			fCellWidth[i] = width;
248 		fPreferredSize.width += fCellWidth[i];
249 	}
250 
251 	// height
252 	font_height fontHeight;
253 	GetFontHeight(&fontHeight);
254 
255 	fPreferredSize.height = ceilf(fontHeight.ascent + fontHeight.descent
256 		+ fontHeight.leading);
257 
258 	if (fPreferredSize.height < B_H_SCROLL_BAR_HEIGHT)
259 		fPreferredSize.height = B_H_SCROLL_BAR_HEIGHT;
260 
261 	float delta = fPreferredSize.width - orgWidth;
262 	ResizeBy(delta, 0);
263 	BScrollBar* scrollBar = fScrollView->ScrollBar(B_HORIZONTAL);
264 	scrollBar->ResizeBy(-delta, 0);
265 	scrollBar->MoveBy(delta, 0);
266 }
267 
268