xref: /haiku/src/apps/fontdemo/ControlView.cpp (revision 1d9d47fc72028bb71b5f232a877231e59cfe2438)
1 /*
2  * Copyright 2006, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Mikael Konradson, mikael.konradson@gmail.com
7  */
8 
9 
10 #include "ControlView.h"
11 #include "messages.h"
12 
13 #include <Button.h>
14 #include <CheckBox.h>
15 #include <Menu.h>
16 #include <MenuField.h>
17 #include <MenuItem.h>
18 #include <MessageRunner.h>
19 #include <Messenger.h>
20 #include <Slider.h>
21 #include <String.h>
22 #include <TextControl.h>
23 #include <Window.h>
24 
25 #include <stdio.h>
26 
27 
28 ControlView::ControlView(BRect rect)
29 	: BView(rect, "ControlView", B_FOLLOW_ALL, B_WILL_DRAW | B_NAVIGABLE_JUMP),
30 	fMessenger(NULL),
31 	fMessageRunner(NULL),
32 	fTextControl(NULL),
33 	fFontMenuField(NULL),
34 	fFontsizeSlider(NULL),
35 	fShearSlider(NULL),
36 	fRotationSlider(NULL),
37 	fSpacingSlider(NULL),
38 	fOutlineSlider(NULL),
39 	fAliasingCheckBox(NULL),
40 	fBoundingboxesCheckBox(NULL),
41 	fCyclingFontButton(NULL),
42 	fFontFamilyMenu(NULL),
43 	fCycleFonts(false),
44 	fFontStyleindex(0)
45 {
46 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
47 }
48 
49 
50 ControlView::~ControlView()
51 {
52 	delete fMessenger;
53 	delete fMessageRunner;
54 }
55 
56 
57 void
58 ControlView::AttachedToWindow()
59 {
60 	BRect rect(Bounds());
61 	rect.InsetBySelf(10, 0);
62 	rect.bottom = rect.top + 18;
63 	rect.OffsetBy(0, 11);
64 
65 	float offsetX = 0;
66 	float offsetY = 0;
67 
68 	fTextControl = new BTextControl(rect, "TextInput", "Text:", "Haiku, inc.", NULL);
69 	fTextControl->SetDivider(29.0);
70 	fTextControl->SetModificationMessage(new BMessage(TEXT_CHANGED_MSG));
71 	AddChild(fTextControl);
72 
73 	rect.OffsetBy(0.0, 27.0);
74 	_AddFontMenu(rect);
75 
76 	rect.OffsetBy(0.0, 29.0);
77 	fFontsizeSlider = new BSlider(rect, "Fontsize", "Size: 50", NULL, 4, 360);
78 	fFontsizeSlider->SetModificationMessage(new BMessage(FONTSIZE_MSG));
79 	fFontsizeSlider->SetValue(50.0);
80 	AddChild(fFontsizeSlider);
81 
82 	// Get the preferred size for the sliders
83 	fFontsizeSlider->GetPreferredSize(&offsetY, &offsetX);
84 	offsetX += 1;
85 
86 	rect.OffsetBy(0.0, offsetX);
87 	fShearSlider = new BSlider(rect, "Shear", "Shear: 90", NULL, 45, 135);
88 	fShearSlider->SetModificationMessage(new BMessage(FONTSHEAR_MSG));
89 	fShearSlider->SetValue(90.0);
90 	AddChild(fShearSlider);
91 
92 	rect.OffsetBy(0.0, offsetX);
93 	fRotationSlider = new BSlider(rect, "Rotation", "Rotation: 0", NULL, 0, 360);
94 	fRotationSlider->SetModificationMessage( new BMessage(ROTATION_MSG));
95 	fRotationSlider->SetValue(0.0);
96 	AddChild(fRotationSlider);
97 
98 	rect.OffsetBy(0.0, offsetX);
99 	fSpacingSlider = new BSlider(rect, "Spacing", "Spacing: 0", NULL, -5, 50);
100 	fSpacingSlider->SetModificationMessage(new BMessage(SPACING_MSG));
101 	fSpacingSlider->SetValue(0.0);
102 	AddChild(fSpacingSlider);
103 
104 	rect.OffsetBy(0.0, offsetX);
105 	fOutlineSlider = new BSlider(rect, "Outline", "Outline:", NULL, 0, 20);
106 	fOutlineSlider->SetModificationMessage(new BMessage(OUTLINE_MSG));
107 	AddChild(fOutlineSlider);
108 
109 	rect.OffsetBy(0.0, offsetX);
110 	fAliasingCheckBox = new BCheckBox(rect, "Aliasing", "Anti-aliased text",
111 		new BMessage(ALIASING_MSG));
112 	fAliasingCheckBox->SetValue(B_CONTROL_ON);
113 	AddChild(fAliasingCheckBox);
114 
115 	rect.OffsetBy(0.0, 22);
116 	fBoundingboxesCheckBox = new BCheckBox(rect, "BoundingBoxes", "Bounding boxes",
117 		new BMessage(BOUNDING_BOX_MSG));
118 	AddChild(fBoundingboxesCheckBox);
119 
120 	rect.OffsetBy(0.0, 22.0);
121 	fCyclingFontButton = new BButton(rect, "Cyclefonts", "Cycle Fonts",
122 		new BMessage(CYCLING_FONTS_MSG));
123 	AddChild(fCyclingFontButton);
124 
125 	fTextControl->SetTarget(this);
126 	fFontsizeSlider->SetTarget(this);
127 	fShearSlider->SetTarget(this);
128 	fRotationSlider->SetTarget(this);
129 	fSpacingSlider->SetTarget(this);
130 	fOutlineSlider->SetTarget(this);
131 	fAliasingCheckBox->SetTarget(this);
132 	fBoundingboxesCheckBox->SetTarget(this);
133 	fCyclingFontButton->SetTarget(this);
134 }
135 
136 
137 void
138 ControlView::Draw(BRect updateRect)
139 {
140 	BRect rect(Bounds());
141 	SetHighColor(tint_color(ViewColor(), B_LIGHTEN_2_TINT));
142 	StrokeLine(rect.LeftTop(), rect.RightTop());
143 	StrokeLine(rect.LeftTop(), rect.LeftBottom());
144 
145 	SetHighColor(tint_color(ViewColor(), B_DARKEN_2_TINT));
146 	StrokeLine(rect.LeftBottom(), rect.RightBottom());
147 	StrokeLine(rect.RightBottom(), rect.RightTop());
148 }
149 
150 
151 void
152 ControlView::MessageReceived(BMessage* msg)
153 {
154 	if (!fMessenger) {
155 		BView::MessageReceived(msg);
156 		return;
157 	}
158 
159 	switch (msg->what) {
160 		case TEXT_CHANGED_MSG:
161 		{
162 			BMessage fontMsg(TEXT_CHANGED_MSG);
163 			fontMsg.AddString("_text", fTextControl->Text());
164 			fMessenger->SendMessage(&fontMsg);
165 			break;
166 		}
167 
168 		case FONTSTYLE_CHANGED_MSG:
169 			_UpdateAndSendStyle(msg);
170 			break;
171 
172 		case FONTFAMILY_CHANGED_MSG:
173 			_UpdateAndSendFamily(msg);
174 			break;
175 
176 		case FONTSIZE_MSG:
177 		{
178 			char buff[256];
179 			sprintf(buff, "Size: %d", static_cast<int>(fFontsizeSlider->Value()));
180 			fFontsizeSlider->SetLabel(buff);
181 
182 			BMessage msg(FONTSIZE_MSG);
183 			msg.AddFloat("_size", static_cast<float>(fFontsizeSlider->Value()));
184 			fMessenger->SendMessage(&msg);
185 			break;
186 		}
187 
188 		case FONTSHEAR_MSG:
189 		{
190 			char buff[256];
191 			sprintf(buff, "Shear: %d", static_cast<int>(fShearSlider->Value()));
192 			fShearSlider->SetLabel(buff);
193 
194 			BMessage msg(FONTSHEAR_MSG);
195 			msg.AddFloat("_shear", static_cast<float>(fShearSlider->Value()));
196 			fMessenger->SendMessage(&msg);
197 			break;
198 		}
199 
200 		case ROTATION_MSG:
201 		{
202 			char buff[256];
203 			sprintf(buff, "Rotation: %d", static_cast<int>(fRotationSlider->Value()));
204 			fRotationSlider->SetLabel(buff);
205 
206 			BMessage msg(ROTATION_MSG);
207 			msg.AddFloat("_rotation", static_cast<float>(fRotationSlider->Value()));
208 			fMessenger->SendMessage(&msg);
209 			break;
210 		}
211 
212 		case SPACING_MSG:
213 		{
214 			char buff[256];
215 			sprintf(buff, "Spacing: %d", (int)fSpacingSlider->Value());
216 			fSpacingSlider->SetLabel(buff);
217 
218 			BMessage msg(SPACING_MSG);
219 			msg.AddFloat("_spacing", static_cast<float>(fSpacingSlider->Value()));
220 			fMessenger->SendMessage(&msg);
221 			break;
222 		}
223 
224 		case ALIASING_MSG:
225 		{
226 			BMessage msg(ALIASING_MSG);
227 			msg.AddBool("_aliased", static_cast<bool>(fAliasingCheckBox->Value()));
228 			fMessenger->SendMessage(&msg);
229 			break;
230 		}
231 
232 		case BOUNDING_BOX_MSG:
233 		{
234 			BMessage msg(BOUNDING_BOX_MSG);
235 			msg.AddBool("_boundingbox", static_cast<bool>(fBoundingboxesCheckBox->Value()));
236 			fMessenger->SendMessage(&msg);
237 			break;
238 		}
239 
240 		case OUTLINE_MSG:
241 		{
242 			int8 outlineVal = (int8)fOutlineSlider->Value();
243 
244 			char buff[256];
245 			sprintf(buff, "Outline: %d", outlineVal);
246 			fOutlineSlider->SetLabel(buff);
247 
248 			fAliasingCheckBox->SetEnabled(outlineVal < 1);
249 			fBoundingboxesCheckBox->SetEnabled(outlineVal < 1);
250 
251 			BMessage msg(OUTLINE_MSG);
252 			msg.AddInt8("_outline", outlineVal);
253 			fMessenger->SendMessage(&msg);
254 			break;
255 		}
256 
257 		case CYCLING_FONTS_MSG:
258 		{
259 			fCyclingFontButton->SetLabel(fCycleFonts ? "Cycle Fonts" : "Stop Cycling");
260 			fCycleFonts = !fCycleFonts;
261 
262 			if (fCycleFonts) {
263 				delete fMessageRunner;
264 				fMessageRunner = new BMessageRunner(this,
265 					new BMessage(CYCLING_FONTS_UPDATE_MSG), 360000*2, -1);
266 			} else {
267 				delete fMessageRunner;
268 				fMessageRunner = NULL;
269 				fFontStyleindex	= 0;
270 				// Delete our MessageRunner and reset the style index
271 			}
272 			break;
273 		}
274 
275 		case CYCLING_FONTS_UPDATE_MSG:
276 		{
277 			int32 familyindex = -1;
278 			BMenuItem* currentFamilyItem = fFontFamilyMenu->FindMarked();
279 
280 			if (currentFamilyItem) {
281 				familyindex = fFontFamilyMenu->IndexOf(currentFamilyItem);
282 		 		const int32 installedStyles = count_font_styles(
283 		 			const_cast<char*>(currentFamilyItem->Label()));
284 
285 		 		BMenu* submenu = currentFamilyItem->Submenu();
286 		 		if (submenu) {
287 		 			BMenuItem* markedStyle = submenu->FindMarked();
288 		 			fFontStyleindex = submenu->IndexOf(markedStyle);
289 				}
290 
291 		 		if (fFontStyleindex < installedStyles - 1)
292 		 			fFontStyleindex++;
293 		 		else {
294 		 			fFontStyleindex = 0;
295 
296 		 			if (familyindex < count_font_families())
297 				 		familyindex++;
298 				 	else
299 			 			familyindex = 0;
300 				}
301 
302 				BMenuItem* newFontFamilyItem = fFontFamilyMenu->ItemAt(familyindex);
303 		 		BMenuItem* newstyleitem = submenu->ItemAt(fFontStyleindex);
304 
305 		 		if (newFontFamilyItem && newstyleitem) {
306 		 			if (msg->AddString("_style", newstyleitem->Label()) != B_OK
307 		 				|| msg->AddString("_family", newFontFamilyItem->Label()) != B_OK) {
308 		 				printf("Failed to add _style or family to the message\n");
309 		 				return;
310 		 			}
311 		 			printf("InstalledStyles(%ld), Font(%s), Style(%s)\n",
312 		 				installedStyles, newFontFamilyItem->Label(),
313 		 				newstyleitem->Label());
314 					_UpdateAndSendStyle(msg);
315 				}
316 			}
317 			break;
318 		}
319 
320 		default:
321 			BView::MessageReceived(msg);
322 	}
323 }
324 
325 
326 void
327 ControlView::SetTarget(BHandler* handler)
328 {
329 	delete fMessenger;
330 	fMessenger = new BMessenger(handler);
331 }
332 
333 
334 void
335 ControlView::_UpdateFontmenus(bool setInitialfont)
336 {
337 	BFont font;
338 	BMenu* stylemenu = NULL;
339 
340 	font_family fontFamilyName, currentFamily;
341 	font_style fontStyleName, currentStyle;
342 
343 	GetFont(&font);
344 	font.GetFamilyAndStyle(&currentFamily, &currentStyle);
345 
346 	const int32 fontfamilies = count_font_families();
347 
348 	fFontFamilyMenu->RemoveItems(0, fFontFamilyMenu->CountItems(), true);
349 
350 	for (int32 i = 0; i < fontfamilies; i++) {
351 		if (get_font_family(i, &fontFamilyName) == B_OK) {
352 			stylemenu = new BMenu(fontFamilyName);
353 			const int32 styles = count_font_styles(fontFamilyName);
354 
355 			BMessage* familyMsg = new BMessage(FONTFAMILY_CHANGED_MSG);
356 			familyMsg->AddString("_family", fontFamilyName);
357 			BMenuItem* familyItem = new BMenuItem(stylemenu, familyMsg);
358 			fFontFamilyMenu->AddItem(familyItem);
359 
360 			for (int32 j = 0; j < styles; j++) {
361 				if (get_font_style(fontFamilyName, j, &fontStyleName) == B_OK) {
362 					BMessage* fontMsg = new BMessage(FONTSTYLE_CHANGED_MSG);
363 					fontMsg->AddString("_family", fontFamilyName);
364 					fontMsg->AddString("_style", fontStyleName);
365 
366 					BMenuItem* styleItem = new BMenuItem(fontStyleName, fontMsg);
367 					styleItem->SetMarked(false);
368 
369 					// setInitialfont is used when we attach the FontField
370 					if (!strcmp(fontStyleName, currentStyle)
371 						&& !strcmp(fontFamilyName, currentFamily)
372 						&& setInitialfont) {
373 						styleItem->SetMarked(true);
374 						familyItem->SetMarked(true);
375 
376 						BString string;
377 						string << currentFamily << " " << currentStyle;
378 
379 						if (fFontMenuField)
380 							fFontMenuField->MenuItem()->SetLabel(string.String());
381 					}
382 					stylemenu->AddItem(styleItem);
383 				}
384 			}
385 		}
386 		stylemenu->SetRadioMode(true);
387 		stylemenu->SetTargetForItems(this);
388 	}
389 
390 	fFontFamilyMenu->SetLabelFromMarked(true);
391 	fFontFamilyMenu->SetTargetForItems(this);
392 }
393 
394 
395 void
396 ControlView::_AddFontMenu(BRect rect)
397 {
398 	fFontFamilyMenu = new BMenu("fontfamlilymenu");
399 
400 	_UpdateFontmenus(true);
401 
402 	fFontMenuField = new BMenuField(rect, "FontMenuField", "Font:", fFontFamilyMenu, true);
403 	fFontMenuField->SetDivider(30.0);
404 	AddChild(fFontMenuField);
405 }
406 
407 
408 void
409 ControlView::_UpdateAndSendFamily(const BMessage* message)
410 {
411 	_DeselectOldItems();
412 
413 	const char* family;
414 	font_style style;
415 
416 	if (message->FindString("_family", &family) == B_OK) {
417 		printf("Family:%s\n\n", family);
418 
419 		BMenuItem* markedItem = fFontFamilyMenu->FindItem(family);
420 		if (!markedItem)
421 			return;
422 
423 		markedItem->SetMarked(true);
424 
425 		get_font_style(font_family(family), 0, &style);
426 
427 		BString string;
428 		string << family << " " << style;
429 
430 		if (fFontMenuField)
431 			fFontMenuField->MenuItem()->SetLabel(string.String());
432 
433 		BMenu* submenu = markedItem->Submenu();
434 
435 		if (submenu) {
436 			BMenuItem* styleItem = submenu->FindItem(style);
437 			if (styleItem && !styleItem->IsMarked())
438 				styleItem->SetMarked(true);
439 		}
440 
441 		BMessage fontMsg(FONTFAMILY_CHANGED_MSG);
442 		if (fontMsg.AddMessage("_fontMessage", message) == B_OK)
443 			fMessenger->SendMessage(&fontMsg);
444 	}
445 }
446 
447 
448 void
449 ControlView::_UpdateAndSendStyle(const BMessage* message)
450 {
451 	_DeselectOldItems();
452 
453 	const char* style;
454 	const char* family;
455 	if (message->FindString("_style", &style) == B_OK
456 		&& message->FindString("_family", &family) == B_OK) {
457 		BMenuItem* familyItem = fFontFamilyMenu->FindItem(family);
458 
459 		if (familyItem && !familyItem->IsMarked()) {
460 			familyItem->SetMarked(true);
461 
462 			BMenu* submenu = familyItem->Submenu();
463 			if (submenu) {
464 				BMenuItem* styleItem = submenu->FindItem(style);
465 				if (styleItem && !styleItem->IsMarked())
466 					styleItem->SetMarked(true);
467 			}
468 		}
469 
470 		BString string;
471 		string << family << " " << style;
472 
473 		if (fFontMenuField)
474 			fFontMenuField->MenuItem()->SetLabel(string.String());
475 	}
476 
477 	BMessage fontMsg(FONTSTYLE_CHANGED_MSG);
478 	if (fontMsg.AddMessage("_fontMessage", message) == B_OK)
479 		fMessenger->SendMessage(&fontMsg);
480 }
481 
482 
483 void
484 ControlView::_DeselectOldItems()
485 {
486 	BMenuItem* oldItem = fFontFamilyMenu->FindMarked();
487 	if (oldItem) {
488 		oldItem->SetMarked(false);
489 
490 		BMenu* submenu = oldItem->Submenu();
491 		if (submenu) {
492 			BMenuItem* marked = submenu->FindMarked();
493 			if (marked)
494 				marked->SetMarked(false);
495 		}
496 	}
497 }
498 
499