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