xref: /haiku/src/apps/webpositive/support/FontSelectionView.cpp (revision 193f6b806fc39c45f5760fa3918b01b79e8796fa)
1 /*
2  * Copyright 2001-2010, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Mark Hogben
7  *		DarkWyrm <bpmagic@columbus.rr.com>
8  *		Axel Dörfler, axeld@pinc-software.de
9  *		Philippe Saint-Pierre, stpere@gmail.com
10  *		Stephan Aßmus <superstippi@gmx.de>
11  */
12 
13 #include "FontSelectionView.h"
14 
15 #include <Box.h>
16 #include <Catalog.h>
17 #include <Locale.h>
18 #include <MenuField.h>
19 #include <MenuItem.h>
20 #include <PopUpMenu.h>
21 #include <String.h>
22 #include <StringView.h>
23 #include <LayoutItem.h>
24 #include <GroupLayoutBuilder.h>
25 
26 #include <stdio.h>
27 
28 #undef TR_CONTEXT
29 #define TR_CONTEXT "Font Selection view"
30 
31 
32 static const float kMinSize = 8.0;
33 static const float kMaxSize = 18.0;
34 
35 static const int32 kMsgSetFamily = 'fmly';
36 static const int32 kMsgSetStyle = 'styl';
37 static const int32 kMsgSetSize = 'size';
38 
39 
40 //	#pragma mark -
41 
42 
43 FontSelectionView::FontSelectionView(const char* name, const char* label,
44 		bool separateStyles, const BFont* currentFont)
45 	:
46 	BHandler(name)
47 {
48 	if (currentFont == NULL)
49 		fCurrentFont = _DefaultFont();
50 	else
51 		fCurrentFont = *currentFont;
52 
53 	fSavedFont = fCurrentFont;
54 
55 	fSizesMenu = new BPopUpMenu("size menu");
56 	fFontsMenu = new BPopUpMenu("font menu");
57 
58 	// font menu
59 	fFontsMenuField = new BMenuField("fonts", label, fFontsMenu, NULL);
60 	fFontsMenuField->SetFont(be_bold_font);
61 
62 	// styles menu, if desired
63 	if (separateStyles) {
64 		fStylesMenu = new BPopUpMenu("styles menu");
65 		fStylesMenuField = new BMenuField("styles", TR("Style:"), fStylesMenu,
66 			NULL);
67 	} else {
68 		fStylesMenu = NULL;
69 		fStylesMenuField = NULL;
70 	}
71 
72 	// size menu
73 	fSizesMenuField = new BMenuField("size", TR("Size:"), fSizesMenu, NULL);
74 	fSizesMenuField->SetAlignment(B_ALIGN_RIGHT);
75 
76 	// preview
77 	fPreviewText = new BStringView("preview text",
78 		TR_CMT("The quick brown fox jumps over the lazy dog.","Don't translate this literally ! Use a phrase showing all chars from A to Z."));
79 
80 	fPreviewText->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
81 	fPreviewText->SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
82 		1.65));
83 	fPreviewText->SetAlignment(B_ALIGN_RIGHT);
84 	_UpdateFontPreview();
85 }
86 
87 
88 FontSelectionView::~FontSelectionView()
89 {
90 	// Some controls may not have been attached...
91 	if (!fPreviewText->Window())
92 		delete fPreviewText;
93 	if (!fSizesMenuField->Window())
94 		delete fSizesMenuField;
95 	if (fStylesMenuField && !fStylesMenuField->Window())
96 		delete fStylesMenuField;
97 	if (!fFontsMenuField->Window())
98 		delete fFontsMenuField;
99 }
100 
101 
102 void
103 FontSelectionView::AttachedToLooper()
104 {
105 	_BuildSizesMenu();
106 	UpdateFontsMenu();
107 }
108 
109 
110 void
111 FontSelectionView::MessageReceived(BMessage* message)
112 {
113 	switch (message->what) {
114 		case kMsgSetSize:
115 		{
116 			int32 size;
117 			if (message->FindInt32("size", &size) != B_OK
118 				|| size == fCurrentFont.Size())
119 				break;
120 
121 			fCurrentFont.SetSize(size);
122 			_UpdateFontPreview();
123 			break;
124 		}
125 
126 		case kMsgSetFamily:
127 		{
128 			const char* family;
129 			if (message->FindString("family", &family) != B_OK)
130 				break;
131 
132 			font_style style;
133 			fCurrentFont.GetFamilyAndStyle(NULL, &style);
134 
135 			BMenuItem* familyItem = fFontsMenu->FindItem(family);
136 			if (familyItem != NULL) {
137 				_SelectCurrentFont(false);
138 
139 				BMenuItem* styleItem;
140 				if (fStylesMenuField != NULL)
141 					styleItem = fStylesMenuField->Menu()->FindMarked();
142 				else {
143 					styleItem = familyItem->Submenu()->FindItem(style);
144 					if (styleItem == NULL)
145 						styleItem = familyItem->Submenu()->ItemAt(0);
146 				}
147 
148 				if (styleItem != NULL) {
149 					styleItem->SetMarked(true);
150 					fCurrentFont.SetFamilyAndStyle(family, styleItem->Label());
151 					_UpdateFontPreview();
152 				}
153 				if (fStylesMenuField != NULL)
154 					_AddStylesToMenu(fCurrentFont, fStylesMenuField->Menu());
155 			}
156 			break;
157 		}
158 
159 		case kMsgSetStyle:
160 		{
161 			const char* family;
162 			const char* style;
163 			if (message->FindString("family", &family) != B_OK
164 				|| message->FindString("style", &style) != B_OK)
165 				break;
166 
167 			BMenuItem *familyItem = fFontsMenu->FindItem(family);
168 			if (!familyItem)
169 				break;
170 
171 			_SelectCurrentFont(false);
172 			familyItem->SetMarked(true);
173 
174 			fCurrentFont.SetFamilyAndStyle(family, style);
175 			_UpdateFontPreview();
176 			break;
177 		}
178 
179 		default:
180 			BHandler::MessageReceived(message);
181 	}
182 }
183 
184 
185 // #pragma mark -
186 
187 
188 void
189 FontSelectionView::SetFont(const BFont& font, float size)
190 {
191 	BFont resizedFont(font);
192 	resizedFont.SetSize(size);
193 	SetFont(resizedFont);
194 }
195 
196 
197 void
198 FontSelectionView::SetFont(const BFont& font)
199 {
200 	if (font == fCurrentFont && font == fSavedFont)
201 		return;
202 
203 	_SelectCurrentFont(false);
204 	fSavedFont = fCurrentFont = font;
205 	_UpdateFontPreview();
206 
207 	_SelectCurrentFont(true);
208 	_SelectCurrentSize(true);
209 }
210 
211 
212 void
213 FontSelectionView::SetSize(float size)
214 {
215 	SetFont(fCurrentFont, size);
216 }
217 
218 
219 const BFont&
220 FontSelectionView::Font() const
221 {
222 	return fCurrentFont;
223 }
224 
225 
226 void
227 FontSelectionView::SetDefaults()
228 {
229 	BFont defaultFont = _DefaultFont();
230 	if (defaultFont == fCurrentFont)
231 		return;
232 
233 	_SelectCurrentFont(false);
234 
235 	fCurrentFont = defaultFont;
236 	_UpdateFontPreview();
237 
238 	_SelectCurrentFont(true);
239 	_SelectCurrentSize(true);
240 }
241 
242 
243 void
244 FontSelectionView::Revert()
245 {
246 	if (!IsRevertable())
247 		return;
248 
249 	_SelectCurrentFont(false);
250 
251 	fCurrentFont = fSavedFont;
252 	_UpdateFontPreview();
253 
254 	_SelectCurrentFont(true);
255 	_SelectCurrentSize(true);
256 }
257 
258 
259 bool
260 FontSelectionView::IsDefaultable()
261 {
262 	return fCurrentFont != _DefaultFont();
263 }
264 
265 
266 bool
267 FontSelectionView::IsRevertable()
268 {
269 	return fCurrentFont != fSavedFont;
270 }
271 
272 
273 void
274 FontSelectionView::UpdateFontsMenu()
275 {
276 	int32 numFamilies = count_font_families();
277 
278 	fFontsMenu->RemoveItems(0, fFontsMenu->CountItems(), true);
279 
280 	BFont font = fCurrentFont;
281 
282 	font_family currentFamily;
283 	font_style currentStyle;
284 	font.GetFamilyAndStyle(&currentFamily, &currentStyle);
285 
286 	for (int32 i = 0; i < numFamilies; i++) {
287 		font_family family;
288 		uint32 flags;
289 		if (get_font_family(i, &family, &flags) != B_OK)
290 			continue;
291 
292 		// if we're setting the fixed font, we only want to show fixed fonts
293 		if (!strcmp(Name(), "fixed") && (flags & B_IS_FIXED) == 0)
294 			continue;
295 
296 		font.SetFamilyAndFace(family, B_REGULAR_FACE);
297 
298 		BMessage* message = new BMessage(kMsgSetFamily);
299 		message->AddString("family", family);
300 		message->AddString("name", Name());
301 
302 		BMenuItem* familyItem;
303 		if (fStylesMenuField != NULL) {
304 			familyItem = new BMenuItem(family, message);
305 		} else {
306 			// Each family item has a submenu with all styles for that font.
307 			BMenu* stylesMenu = new BMenu(family);
308 			_AddStylesToMenu(font, stylesMenu);
309 			familyItem = new BMenuItem(stylesMenu, message);
310 		}
311 
312 		familyItem->SetMarked(strcmp(family, currentFamily) == 0);
313 		fFontsMenu->AddItem(familyItem);
314 		familyItem->SetTarget(this);
315 	}
316 
317 	// Separate styles menu for only the current font.
318 	if (fStylesMenuField != NULL)
319 		_AddStylesToMenu(fCurrentFont, fStylesMenuField->Menu());
320 }
321 
322 
323 // #pragma mark - private
324 
325 
326 BLayoutItem*
327 FontSelectionView::CreateSizesLabelLayoutItem()
328 {
329 	return fSizesMenuField->CreateLabelLayoutItem();
330 }
331 
332 
333 BLayoutItem*
334 FontSelectionView::CreateSizesMenuBarLayoutItem()
335 {
336 	return fSizesMenuField->CreateMenuBarLayoutItem();
337 }
338 
339 
340 BLayoutItem*
341 FontSelectionView::CreateFontsLabelLayoutItem()
342 {
343 	return fFontsMenuField->CreateLabelLayoutItem();
344 }
345 
346 
347 BLayoutItem*
348 FontSelectionView::CreateFontsMenuBarLayoutItem()
349 {
350 	return fFontsMenuField->CreateMenuBarLayoutItem();
351 }
352 
353 
354 BLayoutItem*
355 FontSelectionView::CreateStylesLabelLayoutItem()
356 {
357 	if (fStylesMenuField)
358 		return fStylesMenuField->CreateLabelLayoutItem();
359 	return NULL;
360 }
361 
362 
363 BLayoutItem*
364 FontSelectionView::CreateStylesMenuBarLayoutItem()
365 {
366 	if (fStylesMenuField)
367 		return fStylesMenuField->CreateMenuBarLayoutItem();
368 	return NULL;
369 }
370 
371 
372 BView*
373 FontSelectionView::PreviewBox() const
374 {
375 	return fPreviewText;
376 }
377 
378 
379 // #pragma mark - private
380 
381 
382 BFont
383 FontSelectionView::_DefaultFont() const
384 {
385 	if (strcmp(Name(), "bold") == 0)
386 		return *be_bold_font;
387 	if (strcmp(Name(), "fixed") == 0)
388 		return *be_fixed_font;
389 	else
390 		return *be_plain_font;
391 }
392 
393 
394 void
395 FontSelectionView::_SelectCurrentFont(bool select)
396 {
397 	font_family family;
398 	font_style style;
399 	fCurrentFont.GetFamilyAndStyle(&family, &style);
400 
401 	BMenuItem *item = fFontsMenu->FindItem(family);
402 	if (item != NULL) {
403 		item->SetMarked(select);
404 
405 		if (item->Submenu() != NULL) {
406 			item = item->Submenu()->FindItem(style);
407 			if (item != NULL)
408 				item->SetMarked(select);
409 		}
410 	}
411 }
412 
413 
414 void
415 FontSelectionView::_SelectCurrentSize(bool select)
416 {
417 	char label[16];
418 	snprintf(label, sizeof(label), "%ld", (int32)fCurrentFont.Size());
419 
420 	BMenuItem* item = fSizesMenu->FindItem(label);
421 	if (item != NULL)
422 		item->SetMarked(select);
423 }
424 
425 
426 void
427 FontSelectionView::_UpdateFontPreview()
428 {
429 	fPreviewText->SetFont(&fCurrentFont);
430 }
431 
432 
433 void
434 FontSelectionView::_BuildSizesMenu()
435 {
436 	const int32 sizes[] = {7, 8, 9, 10, 11, 12, 13, 14, 18, 21, 24, 0};
437 
438 	// build size menu
439 	for (int32 i = 0; sizes[i]; i++) {
440 		int32 size = sizes[i];
441 		if (size < kMinSize || size > kMaxSize)
442 			continue;
443 
444 		char label[32];
445 		snprintf(label, sizeof(label), "%ld", size);
446 
447 		BMessage* message = new BMessage(kMsgSetSize);
448 		message->AddInt32("size", size);
449 		message->AddString("name", Name());
450 
451 		BMenuItem* item = new BMenuItem(label, message);
452 		if (size == fCurrentFont.Size())
453 			item->SetMarked(true);
454 
455 		fSizesMenu->AddItem(item);
456 		item->SetTarget(this);
457 	}
458 }
459 
460 
461 void
462 FontSelectionView::_AddStylesToMenu(const BFont& font, BMenu* stylesMenu) const
463 {
464 	stylesMenu->RemoveItems(0, stylesMenu->CountItems(), true);
465 	stylesMenu->SetRadioMode(true);
466 
467 	font_family family;
468 	font_style style;
469 	font.GetFamilyAndStyle(&family, &style);
470 	BString currentStyle(style);
471 
472 	int32 numStyles = count_font_styles(family);
473 
474 	for (int32 j = 0; j < numStyles; j++) {
475 		if (get_font_style(family, j, &style) != B_OK)
476 			continue;
477 
478 		BMessage* message = new BMessage(kMsgSetStyle);
479 		message->AddString("family", (char*)family);
480 		message->AddString("style", (char*)style);
481 
482 		BMenuItem* item = new BMenuItem(style, message);
483 		item->SetMarked(currentStyle == style);
484 
485 		stylesMenu->AddItem(item);
486 		item->SetTarget(this);
487 	}
488 }
489 
490