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