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