1 //------------------------------------------------------------------------------ 2 // Copyright (c) 2001-2002, OpenBeOS 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a 5 // copy of this software and associated documentation files (the "Software"), 6 // to deal in the Software without restriction, including without limitation 7 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 // and/or sell copies of the Software, and to permit persons to whom the 9 // Software is furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 // DEALINGS IN THE SOFTWARE. 21 // 22 // File Name: TextControl.cpp 23 // Author: Frans van Nispen (xlr8@tref.nl) 24 // Description: BTextControl displays text that can act like a control. 25 //------------------------------------------------------------------------------ 26 27 // Standard Includes ----------------------------------------------------------- 28 #include <stdio.h> 29 30 // System Includes ------------------------------------------------------------- 31 #include <TextControl.h> 32 #include <Window.h> 33 #include <Message.h> 34 35 // Project Includes ------------------------------------------------------------ 36 37 // Local Includes -------------------------------------------------------------- 38 #include "TextInput.h" 39 40 // Local Defines --------------------------------------------------------------- 41 42 // Globals --------------------------------------------------------------------- 43 44 //------------------------------------------------------------------------------ 45 BTextControl::BTextControl(BRect frame, const char *name, const char *label, 46 const char *text, BMessage *message, uint32 mask, 47 uint32 flags) 48 : BControl(frame, name, label, message, mask, flags | B_FRAME_EVENTS) 49 { 50 InitData(label, text); 51 52 BRect bounds(Bounds()); 53 54 font_height fh; 55 GetFontHeight(&fh); 56 57 float height = (float)ceil(fh.ascent + fh.descent + fh.leading); 58 float lineHeight = fText->LineHeight(0); 59 60 ResizeTo(bounds.Width(), height + 8); 61 62 BRect textBounds(fText->Bounds()); 63 64 fText->ResizeTo(textBounds.Width(), lineHeight + 4); 65 fText->MoveBy(0, (bounds.Height() - height) / 2.0f); 66 } 67 //------------------------------------------------------------------------------ 68 BTextControl::~BTextControl() 69 { 70 SetModificationMessage(NULL); 71 } 72 //------------------------------------------------------------------------------ 73 BTextControl::BTextControl(BMessage *data) 74 : BControl(data) 75 { 76 InitData(Label(), NULL, data); 77 78 int32 _a_label = B_ALIGN_LEFT; 79 int32 _a_text = B_ALIGN_LEFT; 80 81 if (data->HasInt32("_a_label")) 82 data->FindInt32("_a_label", &_a_label); 83 84 if (data->HasInt32("_a_text")) 85 data->FindInt32("_a_text", &_a_text); 86 87 SetAlignment((alignment)_a_label, (alignment)_a_text); 88 89 if (data->HasFloat("_divide")) 90 data->FindFloat("_a_text", &fDivider); 91 92 if (data->HasMessage("_mod_msg")) 93 { 94 BMessage *_mod_msg = new BMessage; 95 data->FindMessage("_mod_msg", _mod_msg); 96 SetModificationMessage(_mod_msg); 97 } 98 } 99 //------------------------------------------------------------------------------ 100 BArchivable* BTextControl::Instantiate(BMessage *archive) 101 { 102 if (validate_instantiation(archive, "BTextControl")) 103 return new BTextControl(archive); 104 else 105 return NULL; 106 } 107 //------------------------------------------------------------------------------ 108 status_t BTextControl::Archive(BMessage *data, bool deep) const 109 { 110 BView::Archive(data, deep); 111 112 alignment _a_label, _a_text; 113 114 GetAlignment(&_a_label, &_a_text); 115 116 data->AddInt32("_a_label", _a_label); 117 data->AddInt32("_a_text", _a_text); 118 119 data->AddFloat("_divide", Divider()); 120 121 if (ModificationMessage()) 122 data->AddMessage("_mod_msg", ModificationMessage()); 123 124 return B_OK; 125 } 126 //------------------------------------------------------------------------------ 127 void BTextControl::SetText(const char *text) 128 { 129 if (InvokeKind() != B_CONTROL_INVOKED) 130 return; 131 132 fText->SetText(text); 133 134 if (IsFocus()) 135 fText->SetInitialText(); 136 137 fText->Invalidate(); 138 } 139 //------------------------------------------------------------------------------ 140 const char *BTextControl::Text() const 141 { 142 return fText->Text(); 143 } 144 //------------------------------------------------------------------------------ 145 void BTextControl::SetValue(int32 value) 146 { 147 BControl::SetValue(value); 148 } 149 //------------------------------------------------------------------------------ 150 status_t BTextControl::Invoke(BMessage *msg) 151 { 152 return BControl::Invoke(msg); 153 } 154 //------------------------------------------------------------------------------ 155 BTextView* BTextControl::TextView() const 156 { 157 return fText; 158 } 159 //------------------------------------------------------------------------------ 160 void BTextControl::SetModificationMessage(BMessage *message) 161 { 162 if (fModificationMessage) 163 delete fModificationMessage; 164 165 fModificationMessage = message; 166 } 167 //------------------------------------------------------------------------------ 168 BMessage* BTextControl::ModificationMessage() const 169 { 170 return fModificationMessage; 171 } 172 //------------------------------------------------------------------------------ 173 void BTextControl::SetAlignment(alignment label, alignment text) 174 { 175 fText->SetAlignment(text); 176 fText->AlignTextRect(); 177 178 if (fLabelAlign != label) 179 { 180 fLabelAlign = label; 181 Invalidate(); 182 } 183 } 184 //------------------------------------------------------------------------------ 185 void BTextControl::GetAlignment(alignment *label, alignment *text) const 186 { 187 *label = fLabelAlign; 188 *text = fText->Alignment(); 189 } 190 //------------------------------------------------------------------------------ 191 void BTextControl::SetDivider(float dividing_line) 192 { 193 float dx = fDivider - dividing_line; 194 195 fDivider = dividing_line; 196 197 fText->MoveBy(-dx, 0.0f); 198 fText->ResizeBy(dx, 0.0f); 199 200 if (Window()) 201 { 202 fText->Invalidate(); 203 Invalidate(); 204 } 205 } 206 //------------------------------------------------------------------------------ 207 float BTextControl::Divider() const 208 { 209 return fDivider; 210 } 211 //------------------------------------------------------------------------------ 212 void BTextControl::Draw(BRect updateRect) 213 { 214 rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR), 215 lighten1 = tint_color(no_tint, B_LIGHTEN_1_TINT), 216 lighten2 = tint_color(no_tint, B_LIGHTEN_2_TINT), 217 lightenmax = tint_color(no_tint, B_LIGHTEN_MAX_TINT), 218 darken1 = tint_color(no_tint, B_DARKEN_1_TINT), 219 darken2 = tint_color(no_tint, B_DARKEN_2_TINT), 220 darken4 = tint_color(no_tint, B_DARKEN_4_TINT), 221 darkenmax = tint_color(no_tint, B_DARKEN_MAX_TINT), 222 nav = ui_color(B_KEYBOARD_NAVIGATION_COLOR); 223 224 bool enabled = IsEnabled(); 225 bool active = false; 226 227 if (fText->IsFocus() && Window()->IsActive()) 228 active = true; 229 230 BRect rect(fText->Frame()); 231 rect.InsetBy(-1.0f, -1.0f); 232 233 if (active) 234 { 235 SetHighColor(nav); 236 StrokeRect(rect); 237 } 238 else 239 { 240 if (enabled) 241 SetHighColor(darken4); 242 else 243 SetHighColor(darken2); 244 245 StrokeLine(rect.LeftTop(), rect.LeftBottom()); 246 StrokeLine(rect.LeftTop(), rect.RightTop()); 247 248 SetHighColor(no_tint); 249 StrokeLine(BPoint(rect.left + 1.0f, rect.bottom), rect.RightBottom()); 250 StrokeLine(BPoint(rect.right, rect.top + 1.0f)); 251 } 252 253 rect.InsetBy(-1.0f, -1.0f); 254 255 if (enabled) 256 SetHighColor(darken1); 257 else 258 SetHighColor(no_tint); 259 260 StrokeLine(rect.LeftBottom(), rect.LeftTop()); 261 StrokeLine(rect.RightTop()); 262 263 if (enabled) 264 SetHighColor(lighten2); 265 else 266 SetHighColor(lighten1); 267 268 StrokeLine(BPoint(rect.left + 1.0f, rect.bottom), rect.RightBottom()); 269 StrokeLine(BPoint(rect.right, rect.top + 1.0f), rect.RightBottom()); 270 271 if (Label()) 272 { 273 font_height fh; 274 GetFontHeight(&fh); 275 276 float y = (float)ceil(fh.ascent + fh.descent + fh.leading) + 2.0f; 277 float x; 278 279 switch (fLabelAlign) 280 { 281 case B_ALIGN_RIGHT: 282 x = fDivider - StringWidth(Label()) - 3.0f; 283 break; 284 285 case B_ALIGN_CENTER: 286 x = fDivider - StringWidth(Label()) / 2.0f; 287 break; 288 289 default: 290 x = 3.0f; 291 break; 292 } 293 294 SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 295 IsEnabled() ? B_DARKEN_MAX_TINT : B_DISABLED_LABEL_TINT)); 296 DrawString(Label(), BPoint(x, y)); 297 } 298 } 299 //------------------------------------------------------------------------------ 300 void BTextControl::MouseDown(BPoint where) 301 { 302 if (!fText->IsFocus()) 303 { 304 fText->MakeFocus(true); 305 fText->SelectAll(); 306 } 307 } 308 //------------------------------------------------------------------------------ 309 void BTextControl::AttachedToWindow() 310 { 311 BControl::AttachedToWindow(); 312 313 bool enabled = IsEnabled(); 314 rgb_color textColor; 315 rgb_color color = HighColor(); 316 BFont font; 317 318 fText->GetFontAndColor(0, &font, &color); 319 320 if (enabled) 321 textColor = color; 322 else 323 textColor = tint_color(color, B_LIGHTEN_2_TINT); 324 325 fText->SetFontAndColor(&font, B_FONT_ALL, &textColor); 326 327 if (enabled) 328 { 329 color.red = 255; 330 color.green = 255; 331 color.blue = 255; 332 } 333 else 334 color = tint_color(color, B_LIGHTEN_2_TINT); 335 336 fText->SetViewColor(color); 337 fText->SetLowColor(color); 338 339 fText->MakeEditable(enabled); 340 } 341 //------------------------------------------------------------------------------ 342 void BTextControl::MakeFocus(bool state) 343 { 344 fText->MakeFocus(state); 345 346 if (state) 347 fText->SelectAll(); 348 } 349 //------------------------------------------------------------------------------ 350 void BTextControl::SetEnabled(bool state) 351 { 352 if (IsEnabled() == state) 353 return; 354 355 if (Window()) 356 { 357 fText->MakeEditable(state); 358 359 rgb_color textColor; 360 rgb_color color = {0, 0, 0, 255}; 361 BFont font; 362 363 fText->GetFontAndColor(0, &font, &color); 364 365 if (state) 366 textColor = color; 367 else 368 textColor = tint_color(color, B_DISABLED_LABEL_TINT); 369 370 fText->SetFontAndColor(&font, B_FONT_ALL, &textColor); 371 372 if (state) 373 { 374 color.red = 255; 375 color.green = 255; 376 color.blue = 255; 377 } 378 else 379 color = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 380 B_LIGHTEN_2_TINT); 381 382 fText->SetViewColor(color); 383 fText->SetLowColor(color); 384 385 fText->Invalidate(); 386 Window()->UpdateIfNeeded(); 387 } 388 389 BControl::SetEnabled(state); 390 } 391 //------------------------------------------------------------------------------ 392 void BTextControl::GetPreferredSize(float *width, float *height) 393 { 394 BFont font; 395 GetFont(&font); 396 font_height fh; 397 font.GetHeight(&fh); 398 399 *height = (float)ceil(fh.ascent + fh.descent + fh.leading) + 7.0f; 400 401 // TODO: this one I need to find out 402 *width = 4.0f + (float)ceil(font.StringWidth(Label()))*2.0f; 403 } 404 //------------------------------------------------------------------------------ 405 void BTextControl::ResizeToPreferred() 406 { 407 float w; 408 float h; 409 GetPreferredSize(&w, &h); 410 BView::ResizeTo(w,h); 411 } 412 //------------------------------------------------------------------------------ 413 void BTextControl::SetFlags(uint32 flags) 414 { 415 if (!fSkipSetFlags) 416 { 417 // If the textview is navigable, set it to not navigable if needed 418 // Else if it is not navigable, set it to navigable if needed 419 if (fText->Flags() & B_NAVIGABLE) 420 { 421 if (!(flags & B_NAVIGABLE)) 422 fText->SetFlags(fText->Flags() & ~B_NAVIGABLE); 423 } 424 else 425 { 426 if (flags & B_NAVIGABLE) 427 fText->SetFlags(fText->Flags() | B_NAVIGABLE); 428 } 429 430 // Don't make this one navigable 431 flags &= ~B_NAVIGABLE; 432 } 433 434 BView::SetFlags(flags); 435 } 436 //------------------------------------------------------------------------------ 437 void BTextControl::MessageReceived(BMessage *msg) 438 { 439 switch(msg->what) 440 { 441 case B_SET_PROPERTY: 442 case B_GET_PROPERTY: 443 // TODO 444 break; 445 default: 446 BControl::MessageReceived(msg); 447 break; 448 } 449 } 450 //------------------------------------------------------------------------------ 451 BHandler *BTextControl::ResolveSpecifier(BMessage *msg, int32 index, 452 BMessage *specifier, int32 form, 453 const char *property) 454 { 455 /* 456 BPropertyInfo propInfo(prop_list); 457 BHandler *target = NULL; 458 459 if (propInfo.FindMatch(message, 0, specifier, what, property) < B_OK) 460 return BControl::ResolveSpecifier(message, index, specifier, what, 461 property); 462 else 463 return this; 464 */ 465 return BControl::ResolveSpecifier(msg, index, specifier, form, property); 466 } 467 //------------------------------------------------------------------------------ 468 status_t BTextControl::GetSupportedSuites(BMessage *data) 469 { 470 return BControl::GetSupportedSuites(data); 471 } 472 //------------------------------------------------------------------------------ 473 void BTextControl::MouseUp(BPoint pt) 474 { 475 BControl::MouseUp(pt); 476 } 477 //------------------------------------------------------------------------------ 478 void BTextControl::MouseMoved(BPoint pt, uint32 code, const BMessage *msg) 479 { 480 BControl::MouseMoved(pt, code, msg); 481 } 482 //------------------------------------------------------------------------------ 483 void BTextControl::DetachedFromWindow() 484 { 485 BControl::DetachedFromWindow(); 486 } 487 //------------------------------------------------------------------------------ 488 void BTextControl::AllAttached() 489 { 490 BControl::AllAttached(); 491 } 492 //------------------------------------------------------------------------------ 493 void BTextControl::AllDetached() 494 { 495 BControl::AllDetached(); 496 } 497 //------------------------------------------------------------------------------ 498 void BTextControl::FrameMoved(BPoint newPosition) 499 { 500 BControl::FrameMoved(newPosition); 501 } 502 //------------------------------------------------------------------------------ 503 void BTextControl::FrameResized(float newWidth, float newHeight) 504 { 505 BControl::FrameResized(newWidth, newHeight); 506 } 507 //------------------------------------------------------------------------------ 508 void BTextControl::WindowActivated(bool active) 509 { 510 if (fText->IsFocus()) 511 Draw(Bounds()); 512 } 513 //------------------------------------------------------------------------------ 514 status_t BTextControl::Perform(perform_code d, void *arg) 515 { 516 return BControl::Perform(d, arg); 517 } 518 //------------------------------------------------------------------------------ 519 void BTextControl::_ReservedTextControl1() {} 520 void BTextControl::_ReservedTextControl2() {} 521 void BTextControl::_ReservedTextControl3() {} 522 void BTextControl::_ReservedTextControl4() {} 523 //------------------------------------------------------------------------------ 524 BTextControl &BTextControl::operator=(const BTextControl&) 525 { 526 return *this; 527 } 528 //------------------------------------------------------------------------------ 529 void BTextControl::CommitValue() 530 { 531 } 532 //------------------------------------------------------------------------------ 533 void BTextControl::InitData(const char *label, const char *initial_text, 534 BMessage *data) 535 { 536 BRect bounds(Bounds()); 537 538 fText = NULL; 539 //fLabel = NULL; 540 fModificationMessage = NULL; 541 fLabelAlign = B_ALIGN_LEFT; 542 fDivider = 0.0f; 543 fPrevWidth = 0; 544 fPrevHeight = 0; 545 //fClean = true; 546 fSkipSetFlags = false; 547 548 int32 flags = 0; 549 550 BFont font(be_bold_font); 551 552 if (!data || !data->HasString("_fname")) 553 flags = 1; 554 555 if (!data || !data->HasFloat("_fflt")) 556 flags |= 2; 557 558 if (flags != 0) 559 SetFont(&font, flags); 560 561 if (label) 562 fDivider = bounds.Width() / 2.0f; 563 564 if (Flags() & B_NAVIGABLE) 565 { 566 fSkipSetFlags = true; 567 SetFlags(Flags() & ~B_NAVIGABLE); 568 fSkipSetFlags = false; 569 } 570 571 if (data) 572 fText = (_BTextInput_*)FindView("_input_"); 573 else 574 { 575 BRect frame(fDivider, bounds.top + 2.0f, bounds.right - 2.0f, 576 bounds.bottom - 2.0f); 577 BRect textRect(frame.OffsetToCopy(0.0f, 0.0f)); 578 579 fText = new _BTextInput_(frame, textRect, 580 B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, B_WILL_DRAW | B_FRAME_EVENTS | 581 B_NAVIGABLE); 582 583 AddChild(fText); 584 585 SetText(initial_text); 586 fText->SetAlignment(B_ALIGN_LEFT); 587 fText->AlignTextRect(); 588 } 589 } 590 //------------------------------------------------------------------------------ 591 592 /* 593 * $Log $ 594 * 595 * $Id $ 596 * 597 */ 598 599