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