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