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