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
39static const int32 kMsgSetAntialiasing = 'anti';
40static const int32 kMsgSetHinting = 'hint';
41static const int32 kMsgSetAverageWeight = 'avrg';
42static const char* kSubpixelLabel = B_TRANSLATE_MARK("LCD subpixel");
43static const char* kGrayscaleLabel = B_TRANSLATE_MARK("Grayscale");
44static const char* kNoHintingLabel = B_TRANSLATE_MARK("Off");
45static const char* kMonospacedHintingLabel =
46	B_TRANSLATE_MARK("Monospaced fonts only");
47static const char* kFullHintingLabel = B_TRANSLATE_MARK("On");
48
49
50// #pragma mark - private libbe API
51
52
53enum {
54	HINTING_MODE_OFF = 0,
55	HINTING_MODE_ON,
56	HINTING_MODE_MONOSPACED_ONLY
57};
58
59static const uint8 kDefaultHintingMode = HINTING_MODE_ON;
60static const unsigned char kDefaultAverageWeight = 120;
61static const bool kDefaultSubpixelAntialiasing = false;
62
63extern void set_subpixel_antialiasing(bool subpix);
64extern status_t get_subpixel_antialiasing(bool* subpix);
65extern void set_hinting_mode(uint8 hinting);
66extern status_t get_hinting_mode(uint8* hinting);
67extern void set_average_weight(unsigned char averageWeight);
68extern status_t get_average_weight(unsigned char* averageWeight);
69
70
71//	#pragma mark -
72
73
74AntialiasingSettingsView::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
166AntialiasingSettingsView::~AntialiasingSettingsView()
167{
168}
169
170
171void
172AntialiasingSettingsView::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
185void
186AntialiasingSettingsView::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
239void
240AntialiasingSettingsView::_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
261void
262AntialiasingSettingsView::_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
283void
284AntialiasingSettingsView::_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
297void
298AntialiasingSettingsView::_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
321void
322AntialiasingSettingsView::_SetCurrentAverageWeight()
323{
324	fAverageWeightControl->SetValue(fCurrentAverageWeight);
325}
326
327
328void
329AntialiasingSettingsView::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
348bool
349AntialiasingSettingsView::IsDefaultable()
350{
351	return fCurrentSubpixelAntialiasing != kDefaultSubpixelAntialiasing
352		|| fCurrentHinting != kDefaultHintingMode
353		|| fCurrentAverageWeight != kDefaultAverageWeight;
354}
355
356
357bool
358AntialiasingSettingsView::IsRevertable()
359{
360	return fCurrentSubpixelAntialiasing != fSavedSubpixelAntialiasing
361		|| fCurrentHinting != fSavedHinting
362		|| fCurrentAverageWeight != fSavedAverageWeight;
363}
364
365
366void
367AntialiasingSettingsView::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