xref: /haiku/src/apps/terminal/AppearPrefView.cpp (revision 52c4471a3024d2eb81fe88e2c3982b9f8daa5e56)
1 /*
2  * Copyright 2001-2015, Haiku, Inc.
3  * Copyright 2003-2004 Kian Duffy, myob@users.sourceforge.net
4  * Parts Copyright 1998-1999 Kazuho Okui and Takashi Murai.
5  * All rights reserved. Distributed under the terms of the MIT license.
6  */
7 
8 
9 #include "AppearPrefView.h"
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 
14 #include <Button.h>
15 #include <Catalog.h>
16 #include <CharacterSet.h>
17 #include <CharacterSetRoster.h>
18 #include <CheckBox.h>
19 #include <ColorControl.h>
20 #include <LayoutBuilder.h>
21 #include <Locale.h>
22 #include <Menu.h>
23 #include <MenuField.h>
24 #include <MenuItem.h>
25 #include <PopUpMenu.h>
26 #include <TextControl.h>
27 #include <View.h>
28 
29 #include "Colors.h"
30 #include "Globals.h"
31 #include "PrefHandler.h"
32 #include "TermConst.h"
33 #include "TermWindow.h"
34 
35 
36 #undef B_TRANSLATION_CONTEXT
37 #define B_TRANSLATION_CONTEXT "Terminal AppearancePrefView"
38 
39 
40 // #pragma mark -
41 
42 
43 AppearancePrefView::AppearancePrefView(const char* name,
44 		const BMessenger& messenger)
45 	:
46 	BGroupView(name, B_VERTICAL, 5),
47 	fTerminalMessenger(messenger)
48 {
49 	const char* kColorTable[] = {
50 		B_TRANSLATE_MARK("Text"),
51 		B_TRANSLATE_MARK("Background"),
52 		B_TRANSLATE_MARK("Cursor"),
53 		B_TRANSLATE_MARK("Text under cursor"),
54 		B_TRANSLATE_MARK("Selected text"),
55 		B_TRANSLATE_MARK("Selected background"),
56 		"",
57 		B_TRANSLATE_MARK("ANSI black color"),
58 		B_TRANSLATE_MARK("ANSI red color"),
59 		B_TRANSLATE_MARK("ANSI green color"),
60 		B_TRANSLATE_MARK("ANSI yellow color"),
61 		B_TRANSLATE_MARK("ANSI blue color"),
62 		B_TRANSLATE_MARK("ANSI magenta color"),
63 		B_TRANSLATE_MARK("ANSI cyan color"),
64 		B_TRANSLATE_MARK("ANSI white color"),
65 		"",
66 		B_TRANSLATE_MARK("ANSI bright black color"),
67 		B_TRANSLATE_MARK("ANSI bright red color"),
68 		B_TRANSLATE_MARK("ANSI bright green color"),
69 		B_TRANSLATE_MARK("ANSI bright yellow color"),
70 		B_TRANSLATE_MARK("ANSI bright blue color"),
71 		B_TRANSLATE_MARK("ANSI bright magenta color"),
72 		B_TRANSLATE_MARK("ANSI bright cyan color"),
73 		B_TRANSLATE_MARK("ANSI bright white color"),
74 		NULL
75 	};
76 
77 	fBlinkCursor = new BCheckBox(
78 		B_TRANSLATE("Blinking cursor"),
79 			new BMessage(MSG_BLINK_CURSOR_CHANGED));
80 
81 	fAllowBold = new BCheckBox(
82 		B_TRANSLATE("Allow bold text"),
83 			new BMessage(MSG_ALLOW_BOLD_CHANGED));
84 
85 	fUseOptionAsMetaKey = new BCheckBox(
86 		B_TRANSLATE("Use left Option as Meta key"),
87 			new BMessage(MSG_USE_OPTION_AS_META_CHANGED));
88 
89 	fWarnOnExit = new BCheckBox(
90 		B_TRANSLATE("Confirm exit if active programs exist"),
91 			new BMessage(MSG_WARN_ON_EXIT_CHANGED));
92 
93 	BMenu* fontMenu = _MakeFontMenu(MSG_HALF_FONT_CHANGED,
94 		PrefHandler::Default()->getString(PREF_HALF_FONT_FAMILY),
95 		PrefHandler::Default()->getString(PREF_HALF_FONT_STYLE));
96 	fFontField = new BMenuField(B_TRANSLATE("Font:"), fontMenu);
97 
98 	BMenu* sizeMenu = new (std::nothrow) BPopUpMenu(
99 		B_TRANSLATE_COMMENT("Custom", "Window size"));
100 	if (sizeMenu != NULL) {
101 		TermWindow::MakeWindowSizeMenu(sizeMenu);
102 		sizeMenu->SetLabelFromMarked(true);
103 	}
104 	fWindowSizeField = new BMenuField(B_TRANSLATE("Window size:"), sizeMenu);
105 
106 	BMenu* encodingMenu = new (std::nothrow) BPopUpMenu("Text encoding");
107 	if (encodingMenu != NULL) {
108 		TermWindow::MakeEncodingMenu(encodingMenu);
109 		encodingMenu->SetLabelFromMarked(true);
110 	}
111 	fEncodingField = new BMenuField(B_TRANSLATE("Encoding:"), encodingMenu);
112 
113 	BPopUpMenu* schemesPopUp = _MakeColorSchemeMenu(MSG_COLOR_SCHEME_CHANGED,
114 		gColorSchemes);
115 	fColorSchemeField = new BMenuField(B_TRANSLATE("Color scheme:"),
116 		schemesPopUp);
117 
118 	BPopUpMenu* colorsPopUp = _MakeMenu(MSG_COLOR_FIELD_CHANGED, kColorTable,
119 		kColorTable[0]);
120 
121 	fColorField = new BMenuField(B_TRANSLATE("Color:"), colorsPopUp);
122 
123 	fTabTitle = new BTextControl("tabTitle", B_TRANSLATE("Tab title:"), "",
124 		NULL);
125 	fTabTitle->SetModificationMessage(
126 		new BMessage(MSG_TAB_TITLE_SETTING_CHANGED));
127 	fTabTitle->SetToolTip(BString(B_TRANSLATE(
128 		"The pattern specifying the tab titles. The following placeholders\n"
129 		"can be used:")) << "\n" << kToolTipSetTabTitlePlaceholders
130 		<< "\n" << kToolTipCommonTitlePlaceholders);
131 
132 	fWindowTitle = new BTextControl("windowTitle", B_TRANSLATE("Window title:"),
133 		"", NULL);
134 	fWindowTitle->SetModificationMessage(
135 		new BMessage(MSG_WINDOW_TITLE_SETTING_CHANGED));
136 	fWindowTitle->SetToolTip(BString(B_TRANSLATE(
137 		"The pattern specifying the window titles. The following placeholders\n"
138 		"can be used:")) << "\n" << kToolTipSetWindowTitlePlaceholders
139 		<< "\n" << kToolTipCommonTitlePlaceholders);
140 
141 	BLayoutBuilder::Group<>(this)
142 		.SetInsets(5, 5, 5, 5)
143 		.AddGrid(5, 5)
144 			.Add(fTabTitle->CreateLabelLayoutItem(), 0, 0)
145 			.Add(fTabTitle->CreateTextViewLayoutItem(), 1, 0)
146 			.Add(fWindowTitle->CreateLabelLayoutItem(), 0, 1)
147 			.Add(fWindowTitle->CreateTextViewLayoutItem(), 1, 1)
148 			.Add(fWindowSizeField->CreateLabelLayoutItem(), 0, 2)
149 			.Add(fWindowSizeField->CreateMenuBarLayoutItem(), 1, 2)
150 			.Add(fFontField->CreateLabelLayoutItem(), 0, 3)
151 			.Add(fFontField->CreateMenuBarLayoutItem(), 1, 3)
152 			.Add(fEncodingField->CreateLabelLayoutItem(), 0, 4)
153 			.Add(fEncodingField->CreateMenuBarLayoutItem(), 1, 4)
154 			.Add(fColorSchemeField->CreateLabelLayoutItem(), 0, 5)
155 			.Add(fColorSchemeField->CreateMenuBarLayoutItem(), 1, 5)
156 			.Add(fColorField->CreateLabelLayoutItem(), 0, 6)
157 			.Add(fColorField->CreateMenuBarLayoutItem(), 1, 6)
158 			.End()
159 		.AddGlue()
160 		.Add(fColorControl = new BColorControl(BPoint(10, 10),
161 			B_CELLS_32x8, 8.0, "", new BMessage(MSG_COLOR_CHANGED)))
162 		.Add(fBlinkCursor)
163 		.Add(fAllowBold)
164 		.Add(fUseOptionAsMetaKey)
165 		.Add(fWarnOnExit);
166 
167 	fTabTitle->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
168 	fWindowTitle->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
169 	fFontField->SetAlignment(B_ALIGN_RIGHT);
170 	fWindowSizeField->SetAlignment(B_ALIGN_RIGHT);
171 	fEncodingField->SetAlignment(B_ALIGN_RIGHT);
172 	fColorField->SetAlignment(B_ALIGN_RIGHT);
173 	fColorSchemeField->SetAlignment(B_ALIGN_RIGHT);
174 
175 	Revert();
176 
177 	BTextControl* redInput = (BTextControl*)fColorControl->ChildAt(0);
178 	BTextControl* greenInput = (BTextControl*)fColorControl->ChildAt(1);
179 	BTextControl* blueInput = (BTextControl*)fColorControl->ChildAt(2);
180 
181 	redInput->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
182 	greenInput->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
183 	blueInput->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
184 }
185 
186 
187 void
188 AppearancePrefView::Revert()
189 {
190 	PrefHandler* pref = PrefHandler::Default();
191 
192 	fTabTitle->SetText(pref->getString(PREF_TAB_TITLE));
193 	fWindowTitle->SetText(pref->getString(PREF_WINDOW_TITLE));
194 
195 	fBlinkCursor->SetValue(pref->getBool(PREF_BLINK_CURSOR));
196 	fAllowBold->SetValue(pref->getBool(PREF_ALLOW_BOLD));
197 	fUseOptionAsMetaKey->SetValue(pref->getBool(PREF_USE_OPTION_AS_META));
198 	fWarnOnExit->SetValue(pref->getBool(PREF_WARN_ON_EXIT));
199 
200 	_SetCurrentColorScheme();
201 	_SetEncoding(pref->getString(PREF_TEXT_ENCODING));
202 	_SetWindowSize(pref->getInt32(PREF_ROWS), pref->getInt32(PREF_COLS));
203 	fColorControl->SetValue(pref->getRGB(PREF_TEXT_FORE_COLOR));
204 
205 	const char* family = pref->getString(PREF_HALF_FONT_FAMILY);
206 	const char* style = pref->getString(PREF_HALF_FONT_STYLE);
207 	const char* size = pref->getString(PREF_HALF_FONT_SIZE);
208 
209 	_MarkSelectedFont(family, style, size);
210 }
211 
212 
213 void
214 AppearancePrefView::AttachedToWindow()
215 {
216 	fTabTitle->SetTarget(this);
217 	fWindowTitle->SetTarget(this);
218 	fBlinkCursor->SetTarget(this);
219 	fAllowBold->SetTarget(this);
220 	fUseOptionAsMetaKey->SetTarget(this);
221 	fWarnOnExit->SetTarget(this);
222 
223 	fFontField->Menu()->SetTargetForItems(this);
224 	for (int32 i = 0; i < fFontField->Menu()->CountItems(); i++) {
225 		BMenu* fontSizeMenu = fFontField->Menu()->SubmenuAt(i);
226 		if (fontSizeMenu == NULL)
227 			continue;
228 
229 		fontSizeMenu->SetTargetForItems(this);
230 	}
231 
232 	fColorControl->SetTarget(this);
233 	fColorField->Menu()->SetTargetForItems(this);
234 	fColorSchemeField->Menu()->SetTargetForItems(this);
235 	fWindowSizeField->Menu()->SetTargetForItems(this);
236 	fEncodingField->Menu()->SetTargetForItems(this);
237 
238 	_SetCurrentColorScheme();
239 }
240 
241 
242 void
243 
244 AppearancePrefView::MessageReceived(BMessage* msg)
245 {
246 	bool modified = false;
247 
248 	switch (msg->what) {
249 		case MSG_HALF_FONT_CHANGED:
250 		{
251 			const char* family = NULL;
252 			const char* style = NULL;
253 			const char* size = NULL;
254 			if (msg->FindString("font_family", &family) != B_OK
255 				|| msg->FindString("font_style", &style) != B_OK
256 				|| msg->FindString("font_size", &size) != B_OK) {
257 				break;
258 			}
259 
260 			PrefHandler* pref = PrefHandler::Default();
261 			const char* currentFamily
262 				= pref->getString(PREF_HALF_FONT_FAMILY);
263 			const char* currentStyle
264 				= pref->getString(PREF_HALF_FONT_STYLE);
265 			const char* currentSize
266 				= pref->getString(PREF_HALF_FONT_SIZE);
267 
268 			if (currentFamily == NULL || strcmp(currentFamily, family) != 0
269 				|| currentStyle == NULL || strcmp(currentStyle, style) != 0
270 				|| currentSize == NULL || strcmp(currentSize, size) != 0) {
271 				pref->setString(PREF_HALF_FONT_FAMILY, family);
272 				pref->setString(PREF_HALF_FONT_STYLE, style);
273 				pref->setString(PREF_HALF_FONT_SIZE, size);
274 				_MarkSelectedFont(family, style, size);
275 				modified = true;
276 			}
277 			break;
278 		}
279 
280 		case MSG_COLOR_CHANGED:
281 		{
282 			const BMessage* itemMessage
283 				= fColorField->Menu()->FindMarked()->Message();
284 			const char* label = NULL;
285 			if (itemMessage->FindString("label", &label) != B_OK)
286 				break;
287 			rgb_color oldColor = PrefHandler::Default()->getRGB(label);
288 			if (oldColor != fColorControl->ValueAsColor()) {
289 				BMenuItem* item = fColorSchemeField->Menu()->FindMarked();
290 				if (strcmp(item->Label(), gCustomColorScheme.name) != 0) {
291 					item->SetMarked(false);
292 					item = fColorSchemeField->Menu()->FindItem(
293 						gCustomColorScheme.name);
294 					if (item)
295 						item->SetMarked(true);
296 				}
297 
298 				PrefHandler::Default()->setRGB(label,
299 					fColorControl->ValueAsColor());
300 				modified = true;
301 			}
302 			break;
303 		}
304 
305 		case MSG_COLOR_SCHEME_CHANGED:
306 		{
307 			color_scheme* newScheme = NULL;
308 			if (msg->FindPointer("color_scheme",
309 					(void**)&newScheme) == B_OK) {
310 				_ChangeColorScheme(newScheme);
311 				const char* label = NULL;
312 				if (fColorField->Menu()->FindMarked()->Message()->FindString(
313 						"label", &label) == B_OK)
314 					fColorControl->SetValue(
315 						PrefHandler::Default()->getRGB(label));
316 				modified = true;
317 			}
318 			break;
319 		}
320 
321 		case MSG_COLOR_FIELD_CHANGED:
322 		{
323 			const char* label = NULL;
324 			if (msg->FindString("label", &label) == B_OK)
325 				fColorControl->SetValue(PrefHandler::Default()->getRGB(label));
326 			break;
327 		}
328 
329 		case MSG_COLS_CHANGED:
330 		{
331 			int rows = msg->FindInt32("rows");
332 			int columns = msg->FindInt32("columns");
333 			_SetWindowSize(rows, columns);
334 			PrefHandler* handler = PrefHandler::Default();
335 			if (handler->getInt32(PREF_ROWS) != rows) {
336 				PrefHandler::Default()->setInt32(PREF_ROWS, rows);
337 				modified = true;
338 			}
339 			if (handler->getInt32(PREF_COLS) != columns) {
340 				PrefHandler::Default()->setInt32(PREF_COLS, columns);
341 				modified = true;
342 			}
343 
344 			break;
345 		}
346 
347 		case MSG_BLINK_CURSOR_CHANGED:
348 			if (PrefHandler::Default()->getBool(PREF_BLINK_CURSOR)
349 				!= fBlinkCursor->Value()) {
350 					PrefHandler::Default()->setBool(PREF_BLINK_CURSOR,
351 						fBlinkCursor->Value());
352 					modified = true;
353 			}
354 			break;
355 
356 		case MSG_ALLOW_BOLD_CHANGED:
357 			if (PrefHandler::Default()->getBool(PREF_ALLOW_BOLD)
358 				!= fAllowBold->Value()) {
359 					PrefHandler::Default()->setBool(PREF_ALLOW_BOLD,
360 						fAllowBold->Value());
361 					modified = true;
362 			}
363 			break;
364 
365 		case MSG_USE_OPTION_AS_META_CHANGED:
366 			if (PrefHandler::Default()->getBool(PREF_USE_OPTION_AS_META)
367 				!= fUseOptionAsMetaKey->Value()) {
368 					PrefHandler::Default()->setBool(PREF_USE_OPTION_AS_META,
369 						fUseOptionAsMetaKey->Value());
370 					modified = true;
371 			}
372 			break;
373 
374 		case MSG_WARN_ON_EXIT_CHANGED:
375 			if (PrefHandler::Default()->getBool(PREF_WARN_ON_EXIT)
376 				!= fWarnOnExit->Value()) {
377 					PrefHandler::Default()->setBool(PREF_WARN_ON_EXIT,
378 						fWarnOnExit->Value());
379 					modified = true;
380 			}
381 			break;
382 
383 		case MSG_TAB_TITLE_SETTING_CHANGED:
384 		{
385 			BString oldValue(PrefHandler::Default()->getString(PREF_TAB_TITLE));
386 			if (oldValue != fTabTitle->Text()) {
387 				PrefHandler::Default()->setString(PREF_TAB_TITLE,
388 					fTabTitle->Text());
389 				modified = true;
390 			}
391 			break;
392 		}
393 
394 		case MSG_WINDOW_TITLE_SETTING_CHANGED:
395 		{
396 			BString oldValue(PrefHandler::Default()->getString(
397 				PREF_WINDOW_TITLE));
398 			if (oldValue != fWindowTitle->Text()) {
399 				PrefHandler::Default()->setString(PREF_WINDOW_TITLE,
400 					fWindowTitle->Text());
401 				modified = true;
402 			}
403 			break;
404 		}
405 
406 		default:
407 			BView::MessageReceived(msg);
408 			return;
409 	}
410 
411 	if (modified) {
412 		fTerminalMessenger.SendMessage(msg);
413 
414 		BMessenger messenger(this);
415 		messenger.SendMessage(MSG_PREF_MODIFIED);
416 	}
417 }
418 
419 
420 void
421 AppearancePrefView::_ChangeColorScheme(color_scheme* scheme)
422 {
423 	PrefHandler* pref = PrefHandler::Default();
424 
425 	pref->setRGB(PREF_TEXT_FORE_COLOR, scheme->text_fore_color);
426 	pref->setRGB(PREF_TEXT_BACK_COLOR, scheme->text_back_color);
427 	pref->setRGB(PREF_SELECT_FORE_COLOR, scheme->select_fore_color);
428 	pref->setRGB(PREF_SELECT_BACK_COLOR, scheme->select_back_color);
429 	pref->setRGB(PREF_CURSOR_FORE_COLOR, scheme->cursor_fore_color);
430 	pref->setRGB(PREF_CURSOR_BACK_COLOR, scheme->cursor_back_color);
431 	pref->setRGB(PREF_ANSI_BLACK_COLOR, scheme->ansi_colors.black);
432 	pref->setRGB(PREF_ANSI_RED_COLOR, scheme->ansi_colors.red);
433 	pref->setRGB(PREF_ANSI_GREEN_COLOR, scheme->ansi_colors.green);
434 	pref->setRGB(PREF_ANSI_YELLOW_COLOR, scheme->ansi_colors.yellow);
435 	pref->setRGB(PREF_ANSI_BLUE_COLOR, scheme->ansi_colors.blue);
436 	pref->setRGB(PREF_ANSI_MAGENTA_COLOR, scheme->ansi_colors.magenta);
437 	pref->setRGB(PREF_ANSI_CYAN_COLOR, scheme->ansi_colors.cyan);
438 	pref->setRGB(PREF_ANSI_WHITE_COLOR, scheme->ansi_colors.white);
439 	pref->setRGB(PREF_ANSI_BLACK_HCOLOR, scheme->ansi_colors_h.black);
440 	pref->setRGB(PREF_ANSI_RED_HCOLOR, scheme->ansi_colors_h.red);
441 	pref->setRGB(PREF_ANSI_GREEN_HCOLOR, scheme->ansi_colors_h.green);
442 	pref->setRGB(PREF_ANSI_YELLOW_HCOLOR, scheme->ansi_colors_h.yellow);
443 	pref->setRGB(PREF_ANSI_BLUE_HCOLOR, scheme->ansi_colors_h.blue);
444 	pref->setRGB(PREF_ANSI_MAGENTA_HCOLOR, scheme->ansi_colors_h.magenta);
445 	pref->setRGB(PREF_ANSI_CYAN_HCOLOR, scheme->ansi_colors_h.cyan);
446 	pref->setRGB(PREF_ANSI_WHITE_HCOLOR, scheme->ansi_colors_h.white);
447 }
448 
449 
450 void
451 AppearancePrefView::_SetCurrentColorScheme()
452 {
453 	PrefHandler* pref = PrefHandler::Default();
454 
455 	pref->LoadColorScheme(&gCustomColorScheme);
456 
457 	const char* currentSchemeName = NULL;
458 
459 	int32 i = 0;
460 	while (i < gColorSchemes->CountItems()) {
461 		const color_scheme *item = gColorSchemes->ItemAt(i);
462 		i++;
463 
464 		if (gCustomColorScheme == *item) {
465 			currentSchemeName = item->name;
466 			break;
467 		}
468 	}
469 
470 	// If the scheme is not one of the known ones, assume a custom one.
471 	if (currentSchemeName == NULL)
472 		currentSchemeName = "Custom";
473 
474 	for (int32 i = 0; i < fColorSchemeField->Menu()->CountItems(); i++) {
475 		BMenuItem* item = fColorSchemeField->Menu()->ItemAt(i);
476 		if (strcmp(item->Label(), currentSchemeName) == 0) {
477 			item->SetMarked(true);
478 			break;
479 		}
480 	}
481 }
482 
483 
484 void
485 AppearancePrefView::_SetEncoding(const char* name)
486 {
487 	const BPrivate::BCharacterSet* charset
488 		= BPrivate::BCharacterSetRoster::FindCharacterSetByName(name);
489 	if (charset == NULL)
490 		return;
491 	int code = charset->GetConversionID();
492 	for (int32 i = 0; i < fEncodingField->Menu()->CountItems(); i++) {
493 		BMenuItem* item = fEncodingField->Menu()->ItemAt(i);
494 		BMessage* msg = item->Message();
495 		if (msg->FindInt32("op") == code) {
496 			item->SetMarked(true);
497 			break;
498 		}
499 	}
500 }
501 
502 
503 void
504 AppearancePrefView::_SetWindowSize(int rows, int cols)
505 {
506 	for (int32 i = 0; i < fWindowSizeField->Menu()->CountItems(); i++) {
507 		BMenuItem* item = fWindowSizeField->Menu()->ItemAt(i);
508 		BMessage* msg = item->Message();
509 		if (msg->FindInt32("rows") == rows && msg->FindInt32("columns") == cols) {
510 			item->SetMarked(true);
511 			break;
512 		}
513 	}
514 }
515 
516 
517 /*static*/ BMenu*
518 AppearancePrefView::_MakeFontMenu(uint32 command,
519 	const char* defaultFamily, const char* defaultStyle)
520 {
521 	BPopUpMenu* menu = new BPopUpMenu("");
522 	int32 numFamilies = count_font_families();
523 	for (int32 i = 0; i < numFamilies; i++) {
524 		font_family family;
525 		uint32 flags;
526 		if (get_font_family(i, &family, &flags) == B_OK) {
527 			BFont font;
528 			font_style style;
529 			int32 numStyles = count_font_styles(family);
530 			for (int32 j = 0; j < numStyles; j++) {
531 				if (get_font_style(family, j, &style) == B_OK) {
532 					font.SetFamilyAndStyle(family, style);
533 					if (IsFontUsable(font)) {
534 						BMessage* message = new BMessage(command);
535 						const char* size
536 							= PrefHandler::Default()->getString(PREF_HALF_FONT_SIZE);
537 						message->AddString("font_family", family);
538 						message->AddString("font_style", style);
539 						message->AddString("font_size", size);
540 						char fontMenuLabel[134];
541 						snprintf(fontMenuLabel, sizeof(fontMenuLabel),
542 							"%s - %s", family, style);
543 						BMenu* fontSizeMenu = _MakeFontSizeMenu(fontMenuLabel,
544 							MSG_HALF_FONT_CHANGED, family, style, size);
545 						BMenuItem* item = new BMenuItem(fontSizeMenu, message);
546 						menu->AddItem(item);
547 						if (strcmp(defaultFamily, family) == 0
548 							&& strcmp(defaultStyle, style) == 0)
549 							item->SetMarked(true);
550 					}
551 				}
552 			}
553 		}
554 	}
555 
556 	if (menu->FindMarked() == NULL)
557 		menu->ItemAt(0)->SetMarked(true);
558 
559 	return menu;
560 }
561 
562 
563 /*static*/ BMenu*
564 AppearancePrefView::_MakeFontSizeMenu(const char* label, uint32 command,
565 	const char* family, const char* style, const char* size)
566 {
567 	BMenu* menu = new BMenu(label);
568 	menu->SetRadioMode(true);
569 	menu->SetLabelFromMarked(false);
570 
571 	int32 sizes[] = {
572 		8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 28, 32, 36, 0
573 	};
574 
575 	bool found = false;
576 
577 	for (uint32 i = 0; sizes[i]; i++) {
578 		BString fontSize;
579 		fontSize << sizes[i];
580 		BMessage* message = new BMessage(command);
581 		message->AddString("font_family", family);
582 		message->AddString("font_style", style);
583 		message->AddString("font_size", fontSize.String());
584 		BMenuItem* item = new BMenuItem(fontSize.String(), message);
585 		menu->AddItem(item);
586 		if (sizes[i] == atoi(size)) {
587 			item->SetMarked(true);
588 			found = true;
589 		}
590 	}
591 
592 	if (!found) {
593 		for (uint32 i = 0; sizes[i]; i++) {
594 			if (sizes[i] > atoi(size)) {
595 				BMessage* message = new BMessage(command);
596 				message->AddString("font_family", family);
597 				message->AddString("font_style", style);
598 				message->AddString("font_size", size);
599 				BMenuItem* item = new BMenuItem(size, message);
600 				item->SetMarked(true);
601 				menu->AddItem(item, i);
602 				break;
603 			}
604 		}
605 	}
606 
607 	return menu;
608 }
609 
610 
611 /*static*/ BPopUpMenu*
612 AppearancePrefView::_MakeMenu(uint32 msg, const char** items,
613 	const char* defaultItemName)
614 {
615 	BPopUpMenu* menu = new BPopUpMenu("");
616 
617 	while (*items) {
618 		if (strcmp((*items), "") == 0)
619 			menu->AddSeparatorItem();
620 		else {
621 			BMessage* message = new BMessage(msg);
622 			message->AddString("label", *items);
623 			BMenuItem* item = new BMenuItem(B_TRANSLATE(*items), message);
624 			menu->AddItem(item);
625 			if (strcmp(*items, defaultItemName) == 0)
626 				item->SetMarked(true);
627 		}
628 
629 		items++;
630 	}
631 
632 	return menu;
633 }
634 
635 
636 /*static*/ void
637 AppearancePrefView::_MakeColorSchemeMenuItem(uint32 msg, const color_scheme *item,
638 	BPopUpMenu *menu)
639 {
640 	if (item == NULL)
641 		return;
642 
643 	BMessage* message = new BMessage(msg);
644 	message->AddPointer("color_scheme", (const void*)item);
645 	menu->AddItem(new BMenuItem(item->name, message));
646 }
647 
648 
649 /*static*/ BPopUpMenu*
650 AppearancePrefView::_MakeColorSchemeMenu(uint32 msg, BObjectList<const color_scheme> *items)
651 {
652 	BPopUpMenu* menu = new BPopUpMenu("");
653 
654 	FindColorSchemeByName comparator("Default");
655 
656 	const color_scheme* defaultItem = items->FindIf(comparator);
657 
658 	_MakeColorSchemeMenuItem(msg, defaultItem, menu);
659 
660 	int32 i = 0;
661 	while (i < items->CountItems()) {
662 		const color_scheme *item = items->ItemAt(i);
663 		i++;
664 
665 		if (strcmp(item->name, "") == 0)
666 			menu->AddSeparatorItem();
667 		else if (item == defaultItem)
668 			continue;
669 		else
670 			_MakeColorSchemeMenuItem(msg, item, menu);
671 	}
672 
673 	// Add the custom item at the very end
674 	menu->AddSeparatorItem();
675 	_MakeColorSchemeMenuItem(msg, &gCustomColorScheme, menu);
676 
677 	return menu;
678 }
679 
680 
681 void
682 AppearancePrefView::_MarkSelectedFont(const char* family, const char* style,
683 	const char* size)
684 {
685 	char fontMenuLabel[134];
686 	snprintf(fontMenuLabel, sizeof(fontMenuLabel), "%s - %s", family, style);
687 
688 	// mark the selected font
689 	BMenuItem* selectedFont = fFontField->Menu()->FindItem(fontMenuLabel);
690 	if (selectedFont != NULL)
691 		selectedFont->SetMarked(true);
692 
693 	// mark the selected font size on all font menus
694 	for (int32 i = 0; i < fFontField->Menu()->CountItems(); i++) {
695 		BMenu* fontSizeMenu = fFontField->Menu()->SubmenuAt(i);
696 		if (fontSizeMenu == NULL)
697 			continue;
698 
699 		BMenuItem* item = fontSizeMenu->FindItem(size);
700 		if (item != NULL)
701 			item->SetMarked(true);
702 	}
703 }
704