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(¤tFamily, ¤tStyle); 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