xref: /haiku/src/preferences/appearance/AntialiasingSettingsView.cpp (revision 2b76973fa2401f7a5edf68e6470f3d3210cbcff3)
1 /*
2  * Copyright 2008, Stephan Aßmus, <superstippi@gmx.de>
3  * Copyright 2008, Andrej Spielmann, <andrej.spielmann@seh.ox.ac.uk>
4  * All rights reserved. Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include "AntialiasingSettingsView.h"
9 
10 #include <stdio.h>
11 #include <stdlib.h>
12 
13 #include <freetype/config/ftoption.h>
14 	// for detected the availablility of subpixel anti-aliasing
15 
16 #include <Box.h>
17 #include <Catalog.h>
18 #include <GridLayoutBuilder.h>
19 #include <GroupLayoutBuilder.h>
20 #include <Locale.h>
21 #include <MenuField.h>
22 #include <MenuItem.h>
23 #include <PopUpMenu.h>
24 #include <Slider.h>
25 #include <SpaceLayoutItem.h>
26 #include <String.h>
27 #include <TextView.h>
28 
29 #include "APRWindow.h"
30 
31 #undef B_TRANSLATION_CONTEXT
32 #define B_TRANSLATION_CONTEXT "AntialiasingSettingsView"
33 
34 
35 //#define DISABLE_HINTING_CONTROL
36 	// if defined, the hinting menu is disabled (hinting not properly
37 	// implemented)
38 
39 static const int32 kMsgSetAntialiasing = 'anti';
40 static const int32 kMsgSetHinting = 'hint';
41 static const int32 kMsgSetAverageWeight = 'avrg';
42 static const char* kSubpixelLabel = B_TRANSLATE_MARK("LCD subpixel");
43 static const char* kGrayscaleLabel = B_TRANSLATE_MARK("Grayscale");
44 static const char* kNoHintingLabel = B_TRANSLATE_MARK("Off");
45 static const char* kMonospacedHintingLabel =
46 	B_TRANSLATE_MARK("Monospaced fonts only");
47 static const char* kFullHintingLabel = B_TRANSLATE_MARK("On");
48 
49 
50 // #pragma mark - private libbe API
51 
52 
53 enum {
54 	HINTING_MODE_OFF = 0,
55 	HINTING_MODE_ON,
56 	HINTING_MODE_MONOSPACED_ONLY
57 };
58 
59 static const uint8 kDefaultHintingMode = HINTING_MODE_ON;
60 static const unsigned char kDefaultAverageWeight = 120;
61 static const bool kDefaultSubpixelAntialiasing = false;
62 
63 extern void set_subpixel_antialiasing(bool subpix);
64 extern status_t get_subpixel_antialiasing(bool* subpix);
65 extern void set_hinting_mode(uint8 hinting);
66 extern status_t get_hinting_mode(uint8* hinting);
67 extern void set_average_weight(unsigned char averageWeight);
68 extern status_t get_average_weight(unsigned char* averageWeight);
69 
70 
71 //	#pragma mark -
72 
73 
74 AntialiasingSettingsView::AntialiasingSettingsView(const char* name)
75 	: BView(name, 0)
76 {
77 	// collect the current system settings
78 	if (get_subpixel_antialiasing(&fCurrentSubpixelAntialiasing) != B_OK)
79 		fCurrentSubpixelAntialiasing = kDefaultSubpixelAntialiasing;
80 	fSavedSubpixelAntialiasing = fCurrentSubpixelAntialiasing;
81 
82 	if (get_hinting_mode(&fCurrentHinting) != B_OK)
83 		fCurrentHinting = kDefaultHintingMode;
84 	fSavedHinting = fCurrentHinting;
85 
86 	if (get_average_weight(&fCurrentAverageWeight) != B_OK)
87 		fCurrentAverageWeight = kDefaultAverageWeight;
88 	fSavedAverageWeight = fCurrentAverageWeight;
89 
90 	// create the controls
91 
92 	// antialiasing menu
93 	_BuildAntialiasingMenu();
94 	fAntialiasingMenuField = new BMenuField("antialiasing",
95 		B_TRANSLATE("Antialiasing type:"), fAntialiasingMenu);
96 
97 	// "average weight" in subpixel filtering
98 	fAverageWeightControl = new BSlider("averageWeightControl",
99 		B_TRANSLATE("Reduce colored edges filter strength:"),
100 		new BMessage(kMsgSetAverageWeight), 0, 255, B_HORIZONTAL);
101 	fAverageWeightControl->SetLimitLabels(B_TRANSLATE("Off"),
102 		B_TRANSLATE("Strong"));
103 	fAverageWeightControl->SetHashMarks(B_HASH_MARKS_BOTTOM);
104 	fAverageWeightControl->SetHashMarkCount(255 / 15);
105 	fAverageWeightControl->SetEnabled(false);
106 
107 	// hinting menu
108 	_BuildHintingMenu();
109 	fHintingMenuField = new BMenuField("hinting", B_TRANSLATE("Glyph hinting:"),
110 		fHintingMenu);
111 
112 #ifdef DISABLE_HINTING_CONTROL
113 	fHintingMenuField->SetEnabled(false);
114 #endif
115 
116 #ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
117 	// subpixelAntialiasingDisabledLabel
118 	BFont infoFont(*be_plain_font);
119 	infoFont.SetFace(B_ITALIC_FACE);
120 	rgb_color infoColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
121 		B_DARKEN_4_TINT);
122 	// TODO: Replace with layout friendly constructor once available.
123 	BRect textBounds = Bounds();
124 	BTextView* subpixelAntialiasingDisabledLabel = new BTextView(
125 		textBounds, "unavailable label", textBounds, &infoFont, &infoColor,
126 		B_FOLLOW_NONE, B_WILL_DRAW | B_SUPPORTS_LAYOUT);
127 	subpixelAntialiasingDisabledLabel->SetText(B_TRANSLATE(
128 		"Subpixel based anti-aliasing in combination with glyph hinting is not "
129 		"available in this build of Haiku to avoid possible patent issues. To "
130 		"enable this feature, you have to build Haiku yourself and enable "
131 		"certain options in the libfreetype configuration header."));
132 	subpixelAntialiasingDisabledLabel->SetViewColor(
133 		ui_color(B_PANEL_BACKGROUND_COLOR));
134 	subpixelAntialiasingDisabledLabel->MakeEditable(false);
135 	subpixelAntialiasingDisabledLabel->MakeSelectable(false);
136 #endif // !FT_CONFIG_OPTION_SUBPIXEL_RENDERING
137 
138 	SetLayout(new BGroupLayout(B_VERTICAL));
139 
140 	// controls pane
141 	AddChild(BGridLayoutBuilder(10, 10)
142 		.Add(fHintingMenuField->CreateLabelLayoutItem(), 0, 0)
143 		.Add(fHintingMenuField->CreateMenuBarLayoutItem(), 1, 0)
144 
145 		.Add(fAntialiasingMenuField->CreateLabelLayoutItem(), 0, 1)
146 		.Add(fAntialiasingMenuField->CreateMenuBarLayoutItem(), 1, 1)
147 
148 		.Add(fAverageWeightControl, 0, 2, 2)
149 
150 #ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
151 		// hinting+subpixel unavailable info
152 		.Add(subpixelAntialiasingDisabledLabel, 0, 3, 2)
153 #else
154 		.Add(BSpaceLayoutItem::CreateGlue(), 0, 3, 2)
155 #endif
156 
157 		.SetInsets(10, 10, 10, 10)
158 	);
159 
160 	_SetCurrentAntialiasing();
161 	_SetCurrentHinting();
162 	_SetCurrentAverageWeight();
163 }
164 
165 
166 AntialiasingSettingsView::~AntialiasingSettingsView()
167 {
168 }
169 
170 
171 void
172 AntialiasingSettingsView::AttachedToWindow()
173 {
174 	if (Parent() != NULL)
175 		SetViewColor(Parent()->ViewColor());
176 	else
177 		SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
178 
179 	fAntialiasingMenu->SetTargetForItems(this);
180 	fHintingMenu->SetTargetForItems(this);
181 	fAverageWeightControl->SetTarget(this);
182 }
183 
184 
185 void
186 AntialiasingSettingsView::MessageReceived(BMessage *msg)
187 {
188 	switch (msg->what) {
189 		case kMsgSetAntialiasing:
190 		{
191 			bool subpixelAntialiasing;
192 			if (msg->FindBool("antialiasing", &subpixelAntialiasing) != B_OK
193 				|| subpixelAntialiasing == fCurrentSubpixelAntialiasing)
194 				break;
195 
196 			fSavedSubpixelAntialiasing = fCurrentSubpixelAntialiasing;
197 			fCurrentSubpixelAntialiasing = subpixelAntialiasing;
198 			fAverageWeightControl->SetEnabled(fCurrentSubpixelAntialiasing);
199 
200 			set_subpixel_antialiasing(fCurrentSubpixelAntialiasing);
201 
202 			Window()->PostMessage(kMsgUpdate);
203 			break;
204 		}
205 		case kMsgSetHinting:
206 		{
207 			int8 hinting;
208 			if (msg->FindInt8("hinting", &hinting) != B_OK
209 				|| hinting == fCurrentHinting)
210 				break;
211 
212 			fSavedHinting = fCurrentHinting;
213 			fCurrentHinting = hinting;
214 			set_hinting_mode(fCurrentHinting);
215 
216 			Window()->PostMessage(kMsgUpdate);
217 			break;
218 		}
219 		case kMsgSetAverageWeight:
220 		{
221 			int32 averageWeight = fAverageWeightControl->Value();
222 			if (averageWeight == fCurrentAverageWeight)
223 				break;
224 
225 			fSavedAverageWeight = fCurrentAverageWeight;
226 			fCurrentAverageWeight = averageWeight;
227 
228 			set_average_weight(fCurrentAverageWeight);
229 
230 			Window()->PostMessage(kMsgUpdate);
231 			break;
232 		}
233 		default:
234 			BView::MessageReceived(msg);
235 	}
236 }
237 
238 
239 void
240 AntialiasingSettingsView::_BuildAntialiasingMenu()
241 {
242 	fAntialiasingMenu = new BPopUpMenu(B_TRANSLATE("Antialiasing menu"));
243 
244 	BMessage* message = new BMessage(kMsgSetAntialiasing);
245 	message->AddBool("antialiasing", false);
246 
247 	BMenuItem* item
248 		= new BMenuItem(B_TRANSLATE_NOCOLLECT(kGrayscaleLabel), message);
249 
250 	fAntialiasingMenu->AddItem(item);
251 
252 	message = new BMessage(kMsgSetAntialiasing);
253 	message->AddBool("antialiasing", true);
254 
255 	item = new BMenuItem(B_TRANSLATE_NOCOLLECT(kSubpixelLabel), message);
256 
257 	fAntialiasingMenu->AddItem(item);
258 }
259 
260 
261 void
262 AntialiasingSettingsView::_BuildHintingMenu()
263 {
264 	fHintingMenu = new BPopUpMenu(B_TRANSLATE("Hinting menu"));
265 
266 	BMessage* message = new BMessage(kMsgSetHinting);
267 	message->AddInt8("hinting", HINTING_MODE_OFF);
268 	fHintingMenu->AddItem(new BMenuItem(B_TRANSLATE_NOCOLLECT(kNoHintingLabel),
269 		message));
270 
271 	message = new BMessage(kMsgSetHinting);
272 	message->AddInt8("hinting", HINTING_MODE_ON);
273 	fHintingMenu->AddItem(new BMenuItem(
274 		B_TRANSLATE_NOCOLLECT(kFullHintingLabel), message));
275 
276 	message = new BMessage(kMsgSetHinting);
277 	message->AddInt8("hinting", HINTING_MODE_MONOSPACED_ONLY);
278 	fHintingMenu->AddItem(new BMenuItem(
279 		B_TRANSLATE_NOCOLLECT(kMonospacedHintingLabel), message));
280 }
281 
282 
283 void
284 AntialiasingSettingsView::_SetCurrentAntialiasing()
285 {
286 	BMenuItem *item = fAntialiasingMenu->FindItem(
287 		fCurrentSubpixelAntialiasing
288 		? B_TRANSLATE_NOCOLLECT(kSubpixelLabel)
289 		: B_TRANSLATE_NOCOLLECT(kGrayscaleLabel));
290 	if (item != NULL)
291 		item->SetMarked(true);
292 	if (fCurrentSubpixelAntialiasing)
293 		fAverageWeightControl->SetEnabled(true);
294 }
295 
296 
297 void
298 AntialiasingSettingsView::_SetCurrentHinting()
299 {
300 	const char* label;
301 	switch (fCurrentHinting) {
302 		case HINTING_MODE_OFF:
303 			label = kNoHintingLabel;
304 			break;
305 		case HINTING_MODE_ON:
306 			label = kFullHintingLabel;
307 			break;
308 		case HINTING_MODE_MONOSPACED_ONLY:
309 			label = kMonospacedHintingLabel;
310 			break;
311 		default:
312 			return;
313 	}
314 
315 	BMenuItem *item = fHintingMenu->FindItem(B_TRANSLATE_NOCOLLECT(label));
316 	if (item != NULL)
317 		item->SetMarked(true);
318 }
319 
320 
321 void
322 AntialiasingSettingsView::_SetCurrentAverageWeight()
323 {
324 	fAverageWeightControl->SetValue(fCurrentAverageWeight);
325 }
326 
327 
328 void
329 AntialiasingSettingsView::SetDefaults()
330 {
331 	if (!IsDefaultable())
332 		return;
333 
334 	fCurrentSubpixelAntialiasing = kDefaultSubpixelAntialiasing;
335 	fCurrentHinting = kDefaultHintingMode;
336 	fCurrentAverageWeight = kDefaultAverageWeight;
337 
338 	set_subpixel_antialiasing(fCurrentSubpixelAntialiasing);
339 	set_hinting_mode(fCurrentHinting);
340 	set_average_weight(fCurrentAverageWeight);
341 
342 	_SetCurrentAntialiasing();
343 	_SetCurrentHinting();
344 	_SetCurrentAverageWeight();
345 }
346 
347 
348 bool
349 AntialiasingSettingsView::IsDefaultable()
350 {
351 	return fCurrentSubpixelAntialiasing != kDefaultSubpixelAntialiasing
352 		|| fCurrentHinting != kDefaultHintingMode
353 		|| fCurrentAverageWeight != kDefaultAverageWeight;
354 }
355 
356 
357 bool
358 AntialiasingSettingsView::IsRevertable()
359 {
360 	return fCurrentSubpixelAntialiasing != fSavedSubpixelAntialiasing
361 		|| fCurrentHinting != fSavedHinting
362 		|| fCurrentAverageWeight != fSavedAverageWeight;
363 }
364 
365 
366 void
367 AntialiasingSettingsView::Revert()
368 {
369 	if (!IsRevertable())
370 		return;
371 
372 	fCurrentSubpixelAntialiasing = fSavedSubpixelAntialiasing;
373 	fCurrentHinting = fSavedHinting;
374 	fCurrentAverageWeight = fSavedAverageWeight;
375 
376 	set_subpixel_antialiasing(fCurrentSubpixelAntialiasing);
377 	set_hinting_mode(fCurrentHinting);
378 	set_average_weight(fCurrentAverageWeight);
379 
380 	_SetCurrentAntialiasing();
381 	_SetCurrentHinting();
382 	_SetCurrentAverageWeight();
383 }
384