xref: /haiku/src/apps/fontdemo/ControlView.cpp (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
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) {
298 					BMenuItem* markedStyle = submenu->FindMarked();
299 					fFontStyleindex = submenu->IndexOf(markedStyle);
300 				}
301 
302 				if (fFontStyleindex < installedStyles - 1)
303 					fFontStyleindex++;
304 				else {
305 					fFontStyleindex = 0;
306 
307 					if (familyindex < count_font_families() - 1)
308 						familyindex++;
309 					else
310 						familyindex = 0;
311 				}
312 
313 				BMenuItem* newFontFamilyItem = fFontFamilyMenu->ItemAt(familyindex);
314 				BMenuItem* newstyleitem = submenu->ItemAt(fFontStyleindex);
315 
316 				if (newFontFamilyItem && newstyleitem) {
317 					if (msg->AddString("_style", newstyleitem->Label()) != B_OK
318 						|| msg->AddString("_family", newFontFamilyItem->Label()) != B_OK) {
319 						printf("Failed to add style or family to the message\n");
320 						return;
321 					}
322 					printf("InstalledStyles(%" B_PRId32 "), Font(%s), Style(%s)\n",
323 						installedStyles, newFontFamilyItem->Label(),
324 						newstyleitem->Label());
325 					_UpdateAndSendStyle(msg);
326 				}
327 			}
328 			break;
329 		}
330 
331 		default:
332 			BView::MessageReceived(msg);
333 	}
334 }
335 
336 
337 void
338 ControlView::SetTarget(BHandler* handler)
339 {
340 	delete fMessenger;
341 	fMessenger = new BMessenger(handler);
342 	fDrawingModeMenu->SetTargetForItems(handler);
343 }
344 
345 
346 void
347 ControlView::_UpdateFontmenus(bool setInitialfont)
348 {
349 	BFont font;
350 	BMenu* stylemenu = NULL;
351 
352 	font_family fontFamilyName, currentFamily;
353 	font_style fontStyleName, currentStyle;
354 
355 	GetFont(&font);
356 	font.GetFamilyAndStyle(&currentFamily, &currentStyle);
357 
358 	const int32 fontfamilies = count_font_families();
359 
360 	fFontFamilyMenu->RemoveItems(0, fFontFamilyMenu->CountItems(), true);
361 
362 	for (int32 i = 0; i < fontfamilies; i++) {
363 		if (get_font_family(i, &fontFamilyName) == B_OK) {
364 			stylemenu = new BMenu(fontFamilyName);
365 			stylemenu->SetLabelFromMarked(false);
366 			const int32 styles = count_font_styles(fontFamilyName);
367 
368 			BMessage* familyMsg = new BMessage(FONTFAMILY_CHANGED_MSG);
369 			familyMsg->AddString("_family", fontFamilyName);
370 			BMenuItem* familyItem = new BMenuItem(stylemenu, familyMsg);
371 			fFontFamilyMenu->AddItem(familyItem);
372 
373 			for (int32 j = 0; j < styles; j++) {
374 				if (get_font_style(fontFamilyName, j, &fontStyleName) == B_OK) {
375 					BMessage* fontMsg = new BMessage(FONTSTYLE_CHANGED_MSG);
376 					fontMsg->AddString("_family", fontFamilyName);
377 					fontMsg->AddString("_style", fontStyleName);
378 
379 					BMenuItem* styleItem = new BMenuItem(fontStyleName, fontMsg);
380 					styleItem->SetMarked(false);
381 
382 					// setInitialfont is used when we attach the FontField
383 					if (!strcmp(fontStyleName, currentStyle)
384 						&& !strcmp(fontFamilyName, currentFamily)
385 						&& setInitialfont) {
386 						styleItem->SetMarked(true);
387 						familyItem->SetMarked(true);
388 
389 						BString string;
390 						string << currentFamily << " " << currentStyle;
391 
392 						if (fFontMenuField)
393 							fFontMenuField->MenuItem()->SetLabel(string.String());
394 					}
395 					stylemenu->AddItem(styleItem);
396 				}
397 			}
398 
399 			stylemenu->SetRadioMode(true);
400 			stylemenu->SetTargetForItems(this);
401 		}
402 	}
403 
404 	fFontFamilyMenu->SetLabelFromMarked(false);
405 	fFontFamilyMenu->SetTargetForItems(this);
406 }
407 
408 
409 void
410 ControlView::_AddFontMenu()
411 {
412 	fFontFamilyMenu = new BPopUpMenu("fontfamlilymenu");
413 
414 	fFontMenuField = new BMenuField("FontMenuField",
415 		B_TRANSLATE("Font:"), fFontFamilyMenu);
416 	AddChild(fFontMenuField);
417 
418 	_UpdateFontmenus(true);
419 }
420 
421 
422 void
423 ControlView::_AddDrawingModeMenu()
424 {
425 	fDrawingModeMenu = new BPopUpMenu("drawingmodemenu");
426 
427 	BMessage* drawingMsg = NULL;
428 	drawingMsg = new BMessage(DRAWINGMODE_CHANGED_MSG);
429 	drawingMsg->AddInt32("_mode", B_OP_COPY);
430 	fDrawingModeMenu->AddItem(new BMenuItem("B_OP_COPY", drawingMsg));
431 	fDrawingModeMenu->ItemAt(0)->SetMarked(true);
432 	drawingMsg = new BMessage(DRAWINGMODE_CHANGED_MSG);
433 	drawingMsg->AddInt32("_mode", B_OP_OVER);
434 	fDrawingModeMenu->AddItem(new BMenuItem("B_OP_OVER", drawingMsg));
435 	drawingMsg = new BMessage(DRAWINGMODE_CHANGED_MSG);
436 	drawingMsg->AddInt32("_mode", B_OP_ERASE);
437 	fDrawingModeMenu->AddItem(new BMenuItem("B_OP_ERASE", drawingMsg));
438 	drawingMsg = new BMessage(DRAWINGMODE_CHANGED_MSG);
439 	drawingMsg->AddInt32("_mode", B_OP_INVERT);
440 	fDrawingModeMenu->AddItem(new BMenuItem("B_OP_INVERT", drawingMsg));
441 	drawingMsg = new BMessage(DRAWINGMODE_CHANGED_MSG);
442 	drawingMsg->AddInt32("_mode", B_OP_ADD);
443 	fDrawingModeMenu->AddItem(new BMenuItem("B_OP_ADD", drawingMsg));
444 	drawingMsg = new BMessage(DRAWINGMODE_CHANGED_MSG);
445 	drawingMsg->AddInt32("_mode", B_OP_SUBTRACT);
446 	fDrawingModeMenu->AddItem(new BMenuItem("B_OP_SUBTRACT", drawingMsg));
447 	drawingMsg = new BMessage(DRAWINGMODE_CHANGED_MSG);
448 	drawingMsg->AddInt32("_mode", B_OP_BLEND);
449 	fDrawingModeMenu->AddItem(new BMenuItem("B_OP_BLEND", drawingMsg));
450 	drawingMsg = new BMessage(DRAWINGMODE_CHANGED_MSG);
451 	drawingMsg->AddInt32("_mode", B_OP_MIN);
452 	fDrawingModeMenu->AddItem(new BMenuItem("B_OP_MIN", drawingMsg));
453 	drawingMsg = new BMessage(DRAWINGMODE_CHANGED_MSG);
454 	drawingMsg->AddInt32("_mode", B_OP_MAX);
455 	fDrawingModeMenu->AddItem(new BMenuItem("B_OP_MAX", drawingMsg));
456 	drawingMsg = new BMessage(DRAWINGMODE_CHANGED_MSG);
457 	drawingMsg->AddInt32("_mode", B_OP_SELECT);
458 	fDrawingModeMenu->AddItem(new BMenuItem("B_OP_SELECT", drawingMsg));
459 	drawingMsg = new BMessage(DRAWINGMODE_CHANGED_MSG);
460 	drawingMsg->AddInt32("_mode", B_OP_ALPHA);
461 	fDrawingModeMenu->AddItem(new BMenuItem("B_OP_ALPHA", drawingMsg));
462 
463 	fDrawingModeMenu->SetLabelFromMarked(true);
464 
465 	BMenuField* drawingModeMenuField = new BMenuField("FontMenuField",
466 		B_TRANSLATE("Drawing mode:"), fDrawingModeMenu);
467 	AddChild(drawingModeMenuField);
468 }
469 
470 
471 void
472 ControlView::_UpdateAndSendFamily(const BMessage* message)
473 {
474 	_DeselectOldItems();
475 
476 	font_family family;
477 	font_style style;
478 
479 	if (message->FindString("_family", (const char **)&family) == B_OK) {
480 		char* name;
481 		type_code typeFound = 0;
482 		int32 countFound = 0;
483 		if (message->GetInfo(B_ANY_TYPE, 0, &name, &typeFound,
484 				&countFound) == B_OK) {
485 			if (typeFound == B_STRING_TYPE) {
486 				BString string;
487 				if (message->FindString(name, 0, &string) == B_OK)
488 					printf("Family: %s\n", string.String());
489 			}
490 		}
491 
492 		BMenuItem* markedItem = fFontFamilyMenu->FindItem(family);
493 		if (!markedItem)
494 			return;
495 
496 		markedItem->SetMarked(true);
497 
498 		get_font_style(family, 0, &style);
499 
500 		BString string;
501 		string << family << " " << style;
502 
503 		if (fFontMenuField)
504 			fFontMenuField->MenuItem()->SetLabel(string.String());
505 
506 		BMenu* submenu = markedItem->Submenu();
507 
508 		if (submenu) {
509 			BMenuItem* styleItem = submenu->FindItem(style);
510 			if (styleItem && !styleItem->IsMarked())
511 				styleItem->SetMarked(true);
512 		}
513 
514 		BMessage fontMsg(FONTFAMILY_CHANGED_MSG);
515 		if (fontMsg.AddMessage("_fontMessage", message) == B_OK)
516 			fMessenger->SendMessage(&fontMsg);
517 	}
518 }
519 
520 
521 void
522 ControlView::_UpdateAndSendStyle(const BMessage* message)
523 {
524 	_DeselectOldItems();
525 
526 	const char* style;
527 	const char* family;
528 	if (message->FindString("_style", &style) == B_OK
529 		&& message->FindString("_family", &family) == B_OK) {
530 		BMenuItem* familyItem = fFontFamilyMenu->FindItem(family);
531 
532 		if (familyItem && !familyItem->IsMarked()) {
533 			familyItem->SetMarked(true);
534 
535 			BMenu* submenu = familyItem->Submenu();
536 			if (submenu) {
537 				BMenuItem* styleItem = submenu->FindItem(style);
538 				if (styleItem && !styleItem->IsMarked())
539 					styleItem->SetMarked(true);
540 			}
541 			printf("Family: %s, Style: %s\n", family, style);
542 		}
543 
544 		BString string;
545 		string << family << " " << style;
546 
547 		if (fFontMenuField)
548 			fFontMenuField->MenuItem()->SetLabel(string.String());
549 	}
550 
551 	BMessage fontMsg(FONTSTYLE_CHANGED_MSG);
552 	if (fontMsg.AddMessage("_fontMessage", message) == B_OK)
553 		fMessenger->SendMessage(&fontMsg);
554 }
555 
556 
557 void
558 ControlView::_DeselectOldItems()
559 {
560 	BMenuItem* oldItem = fFontFamilyMenu->FindMarked();
561 	if (oldItem) {
562 		oldItem->SetMarked(false);
563 
564 		BMenu* submenu = oldItem->Submenu();
565 		if (submenu) {
566 			BMenuItem* marked = submenu->FindMarked();
567 			if (marked)
568 				marked->SetMarked(false);
569 		}
570 	}
571 }
572 
573