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