xref: /haiku/src/apps/terminal/AppearPrefView.cpp (revision 857b0c2bef2de29d8f02f6daf7c8379bf782dccb)
1 /*
2  * Copyright 2001-2009, 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 <Menu.h>
16 #include <MenuField.h>
17 #include <MenuItem.h>
18 #include <PopUpMenu.h>
19 #include <TextControl.h>
20 #include <View.h>
21 
22 #include "MenuUtil.h"
23 #include "PrefHandler.h"
24 #include "TermConst.h"
25 
26 
27 
28 AppearancePrefView::AppearancePrefView(BRect frame, const char *name,
29 		BMessenger messenger)
30 	: PrefView(frame, name),
31 	fAppearancePrefViewMessenger(messenger)
32 {
33   	const char *color_tbl[] = {
34 		PREF_TEXT_FORE_COLOR,
35 		PREF_TEXT_BACK_COLOR,
36 		PREF_CURSOR_FORE_COLOR,
37 		PREF_CURSOR_BACK_COLOR,
38 		PREF_SELECT_FORE_COLOR,
39 		PREF_SELECT_BACK_COLOR,
40 #if 0
41 		"",
42 		PREF_IM_FORE_COLOR,
43 		PREF_IM_BACK_COLOR,
44 		PREF_IM_SELECT_COLOR,
45 		"",
46 		PREF_ANSI_BLACK_COLOR,
47 		PREF_ANSI_RED_COLOR,
48 		PREF_ANSI_GREEN_COLOR,
49 		PREF_ANSI_YELLOW_COLOR,
50 		PREF_ANSI_BLUE_COLOR,
51 		PREF_ANSI_MAGENTA_COLOR,
52 		PREF_ANSI_CYAN_COLOR,
53 		PREF_ANSI_WHITE_COLOR,
54 #endif
55 		NULL
56   	};
57 
58 	float greenDividerSize = StringWidth("Green:") + 8.0;
59 	float colorDividerSize = StringWidth("Color:") + 8.0;
60 
61 	BRect r(5, 5, 261, 25);
62 
63 	BMenu *menu = _MakeFontMenu(MSG_HALF_FONT_CHANGED,
64 		PrefHandler::Default()->getString(PREF_HALF_FONT_FAMILY));
65 	fFont = new BMenuField(r, "font", "Font:", menu);
66 	fFont->SetDivider(colorDividerSize);
67 	fFont->SetAlignment(B_ALIGN_RIGHT);
68 	AddChild(fFont);
69 
70 	r.OffsetBy(r.Width() + 10, 0);
71 	menu = _MakeSizeMenu(MSG_HALF_SIZE_CHANGED,
72 		PrefHandler::Default()->getInt32(PREF_HALF_FONT_SIZE));
73 	fFontSize = new BMenuField(r, "size", "Size:", menu);
74 	fFontSize->SetDivider(greenDividerSize);
75 	fFontSize->SetAlignment(B_ALIGN_RIGHT);
76 	AddChild(fFontSize);
77 
78 	r.OffsetBy(-r.Width() - 10,r.Height() + 10);
79 	fColorField = new BMenuField(r, "color", "Color:",
80 		MakeMenu(MSG_COLOR_FIELD_CHANGED, color_tbl, color_tbl[0]));
81 	fColorField->SetDivider(colorDividerSize);
82 	fColorField->SetAlignment(B_ALIGN_RIGHT);
83 	AddChild(fColorField);
84 
85 	fColorControl = SetupColorControl(BPoint(r.left, r.bottom + 10),
86 		B_CELLS_32x8, 8.0, MSG_COLOR_CHANGED);
87 	fColorControl->SetValue(PrefHandler::Default()->getRGB(PREF_TEXT_FORE_COLOR));
88 
89 	BTextControl* redInput = (BTextControl*)fColorControl->ChildAt(0);
90 	BTextControl* greenInput = (BTextControl*)fColorControl->ChildAt(1);
91 	BTextControl* blueInput = (BTextControl*)fColorControl->ChildAt(2);
92 
93 	redInput->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
94 	greenInput->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
95 	blueInput->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
96 
97 	redInput->SetDivider(greenDividerSize);
98 	greenInput->SetDivider(greenDividerSize);
99 	blueInput->SetDivider(greenDividerSize);
100 }
101 
102 
103 void
104 AppearancePrefView::GetPreferredSize(float *_width, float *_height)
105 {
106 	if (_width)
107 		*_width = Bounds().Width();
108 
109 	if (*_height)
110 		*_height = fColorControl->Frame().bottom;
111 }
112 
113 
114 void
115 AppearancePrefView::Revert()
116 {
117 	fColorField->Menu()->ItemAt(0)->SetMarked(true);
118 	fColorControl->SetValue(PrefHandler::Default()->getRGB(PREF_TEXT_FORE_COLOR));
119 
120 	fFont->Menu()->FindItem(PrefHandler::Default()->getString(PREF_HALF_FONT_FAMILY))->SetMarked(true);
121 	fFontSize->Menu()->FindItem(PrefHandler::Default()->getString(PREF_HALF_FONT_FAMILY))->SetMarked(true);
122 }
123 
124 
125 void
126 AppearancePrefView::AttachedToWindow()
127 {
128 	fFontSize->Menu()->SetTargetForItems(this);
129 	fFont->Menu()->SetTargetForItems(this);
130 
131   	fColorControl->SetTarget(this);
132   	fColorField->Menu()->SetTargetForItems(this);
133 }
134 
135 
136 void
137 AppearancePrefView::MessageReceived(BMessage *msg)
138 {
139 	bool modified = false;
140 
141 	switch (msg->what) {
142 		case MSG_HALF_FONT_CHANGED:
143 			if (strcmp(
144 					PrefHandler::Default()->getString(PREF_HALF_FONT_FAMILY),
145 					fFont->Menu()->FindMarked()->Label())) {
146 
147 				PrefHandler::Default()->setString(PREF_HALF_FONT_FAMILY,
148 					fFont->Menu()->FindMarked()->Label());
149 				modified = true;
150 			}
151 			break;
152 
153 		case MSG_HALF_SIZE_CHANGED:
154 			if (strcmp(PrefHandler::Default()->getString(PREF_HALF_FONT_SIZE),
155 					fFontSize->Menu()->FindMarked()->Label())) {
156 
157 				PrefHandler::Default()->setString(PREF_HALF_FONT_SIZE,
158 					fFontSize->Menu()->FindMarked()->Label());
159 				modified = true;
160 			}
161 			break;
162 
163 		case MSG_COLOR_CHANGED: {
164 				rgb_color oldColor = PrefHandler::Default()->getRGB(
165 					fColorField->Menu()->FindMarked()->Label());
166 				if (oldColor != fColorControl->ValueAsColor()) {
167 					PrefHandler::Default()->setRGB(
168 						fColorField->Menu()->FindMarked()->Label(),
169 						fColorControl->ValueAsColor());
170 					modified = true;
171 				}
172 			}
173 			break;
174 
175 		case MSG_COLOR_FIELD_CHANGED:
176 			fColorControl->SetValue(PrefHandler::Default()->getRGB(
177 				fColorField->Menu()->FindMarked()->Label()));
178 			break;
179 
180 		default:
181 			PrefView::MessageReceived(msg);
182 			return;
183 	}
184 
185 	if (modified) {
186 		fAppearancePrefViewMessenger.SendMessage(msg);
187 
188 		BMessenger messenger(this);
189 		messenger.SendMessage(MSG_PREF_MODIFIED);
190 	}
191 }
192 
193 
194 static bool
195 IsFontUsable(const BFont &font)
196 {
197 	// TODO: If BFont::IsFullAndHalfFixed() was implemented, we could
198 	// use that. But I don't think it's easily implementable using
199 	// Freetype.
200 
201 	if (font.IsFixed())
202 		return true;
203 
204 	// manually check if all applicable chars are the same width
205 	char buffer[2] = { ' ', 0 };
206 	int firstWidth = (int)ceilf(font.StringWidth(buffer));
207 
208 	for (int c = ' '+1; c <= 0x7e; c++) {
209 		buffer[0] = c;
210 		int width = (int)ceilf(font.StringWidth(buffer));
211 
212 		if (width != firstWidth)
213 			return false;
214 	}
215 
216 	return true;
217 }
218 
219 
220 BMenu *
221 AppearancePrefView::_MakeFontMenu(uint32 command, const char *defaultFontName)
222 {
223 	BPopUpMenu *menu = new BPopUpMenu("");
224 	int32 numFamilies = count_font_families();
225 	uint32 flags;
226 
227 	for (int32 i = 0; i < numFamilies; i++) {
228 		font_family family;
229 		if (get_font_family(i, &family, &flags) == B_OK) {
230 			BFont font;
231 			font.SetFamilyAndStyle(family, NULL);
232 			if (IsFontUsable(font)) {
233 				BMenuItem *item = new BMenuItem(family, new BMessage(command));
234 				menu->AddItem(item);
235 				if (!strcmp(defaultFontName, family))
236 					item->SetMarked(true);
237 			}
238 		}
239 	}
240 
241 	return menu;
242 }
243 
244 
245 BMenu *
246 AppearancePrefView::_MakeSizeMenu(uint32 command, uint8 defaultSize)
247 {
248 	BPopUpMenu *menu = new BPopUpMenu("size");
249 	int32 sizes[] = {9, 10, 11, 12, 14, 16, 18, 0};
250 
251 	bool found = false;
252 
253 	for (uint32 i = 0; sizes[i]; i++) {
254 		BString string;
255 		string << sizes[i];
256 
257 		BMenuItem *item = new BMenuItem(string.String(), new BMessage(command));
258 		menu->AddItem(item);
259 
260 		if (sizes[i] == defaultSize) {
261 			item->SetMarked(true);
262 			found = true;
263 		}
264 	}
265 	if (!found) {
266 		for (uint32 i = 0; sizes[i]; i++) {
267 			if (sizes[i] > defaultSize) {
268 				BString string;
269 				string << defaultSize;
270 				BMenuItem *item = new BMenuItem(string.String(), new BMessage(command));
271 				item->SetMarked(true);
272 				menu->AddItem(item, i);
273 				break;
274 			}
275 		}
276 	}
277 
278 	return menu;
279 }
280