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
32ControlView::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
56ControlView::~ControlView()
57{
58	delete fMessenger;
59	delete fMessageRunner;
60}
61
62
63void
64ControlView::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
133void
134ControlView::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
147void
148ControlView::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
339void
340ControlView::SetTarget(BHandler* handler)
341{
342	delete fMessenger;
343	fMessenger = new BMessenger(handler);
344	fDrawingModeMenu->SetTargetForItems(handler);
345}
346
347
348void
349ControlView::_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
411void
412ControlView::_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
424void
425ControlView::_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
473void
474ControlView::_UpdateAndSendFamily(const BMessage* message)
475{
476	_DeselectOldItems();
477
478	font_family family;
479	font_style style;
480
481	if (message->FindString("_family", (const char **)&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(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
523void
524ControlView::_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
559void
560ControlView::_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