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