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 BRect bounds(Bounds()); 225 bool enabled = IsEnabled(); 226 bool active = false; 227 228 if (fText->IsFocus() && Window()->IsActive()) 229 active = true; 230 231 BRect rect(fText->Frame()); 232 rect.InsetBy(-1.0f, -1.0f); 233 234 if (active) 235 { 236 SetHighColor(nav); 237 StrokeRect(rect); 238 } 239 else 240 { 241 if (enabled) 242 SetHighColor(darken4); 243 else 244 SetHighColor(darken2); 245 246 StrokeLine(rect.LeftTop(), rect.LeftBottom()); 247 StrokeLine(rect.LeftTop(), rect.RightTop()); 248 249 SetHighColor(no_tint); 250 StrokeLine(BPoint(rect.left + 1.0f, rect.bottom), rect.RightBottom()); 251 StrokeLine(BPoint(rect.right, rect.top + 1.0f)); 252 } 253 254 rect.InsetBy(-1.0f, -1.0f); 255 256 if (enabled) 257 SetHighColor(darken1); 258 else 259 SetHighColor(no_tint); 260 261 StrokeLine(rect.LeftBottom(), rect.LeftTop()); 262 StrokeLine(rect.RightTop()); 263 264 if (enabled) 265 SetHighColor(lighten2); 266 else 267 SetHighColor(lighten1); 268 269 StrokeLine(BPoint(rect.left + 1.0f, rect.bottom), rect.RightBottom()); 270 StrokeLine(BPoint(rect.right, rect.top + 1.0f), rect.RightBottom()); 271 272 if (Label()) 273 { 274 font_height fh; 275 GetFontHeight(&fh); 276 277 float y = (float)ceil(fh.ascent + fh.descent + fh.leading) + 2.0f; 278 float x; 279 280 switch (fLabelAlign) 281 { 282 case B_ALIGN_RIGHT: 283 x = fDivider - StringWidth(Label()) - 3.0f; 284 break; 285 286 case B_ALIGN_CENTER: 287 x = fDivider - StringWidth(Label()) / 2.0f; 288 break; 289 290 default: 291 x = 3.0f; 292 break; 293 } 294 295 SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 296 IsEnabled() ? B_DARKEN_MAX_TINT : B_DISABLED_LABEL_TINT)); 297 DrawString(Label(), BPoint(x, y)); 298 } 299 } 300 //------------------------------------------------------------------------------ 301 void BTextControl::MouseDown(BPoint where) 302 { 303 if (!fText->IsFocus()) 304 { 305 fText->MakeFocus(true); 306 fText->SelectAll(); 307 } 308 } 309 //------------------------------------------------------------------------------ 310 void BTextControl::AttachedToWindow() 311 { 312 BControl::AttachedToWindow(); 313 314 bool enabled = IsEnabled(); 315 rgb_color textColor; 316 rgb_color color = HighColor(); 317 BFont font; 318 319 fText->GetFontAndColor(0, &font, &color); 320 321 if (enabled) 322 textColor = color; 323 else 324 textColor = tint_color(color, B_LIGHTEN_2_TINT); 325 326 fText->SetFontAndColor(&font, B_FONT_ALL, &textColor); 327 328 if (enabled) 329 { 330 color.red = 255; 331 color.green = 255; 332 color.blue = 255; 333 } 334 else 335 color = tint_color(color, B_LIGHTEN_2_TINT); 336 337 fText->SetViewColor(color); 338 fText->SetLowColor(color); 339 340 fText->MakeEditable(enabled); 341 } 342 //------------------------------------------------------------------------------ 343 void BTextControl::MakeFocus(bool state) 344 { 345 fText->MakeFocus(state); 346 347 if (state) 348 fText->SelectAll(); 349 } 350 //------------------------------------------------------------------------------ 351 void BTextControl::SetEnabled(bool state) 352 { 353 if (IsEnabled() == state) 354 return; 355 356 if (Window()) 357 { 358 fText->MakeEditable(state); 359 360 rgb_color textColor; 361 rgb_color color = {0, 0, 0, 255}; 362 BFont font; 363 364 fText->GetFontAndColor(0, &font, &color); 365 366 if (state) 367 textColor = color; 368 else 369 textColor = tint_color(color, B_DISABLED_LABEL_TINT); 370 371 fText->SetFontAndColor(&font, B_FONT_ALL, &textColor); 372 373 if (state) 374 { 375 color.red = 255; 376 color.green = 255; 377 color.blue = 255; 378 } 379 else 380 color = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 381 B_LIGHTEN_2_TINT); 382 383 fText->SetViewColor(color); 384 fText->SetLowColor(color); 385 386 fText->Invalidate(); 387 Window()->UpdateIfNeeded(); 388 } 389 390 BControl::SetEnabled(state); 391 } 392 //------------------------------------------------------------------------------ 393 void BTextControl::GetPreferredSize(float *width, float *height) 394 { 395 BFont font; 396 GetFont(&font); 397 font_height fh; 398 font.GetHeight(&fh); 399 400 *height = (float)ceil(fh.ascent + fh.descent + fh.leading) + 7.0f; 401 402 // TODO: this one I need to find out 403 *width = 4.0f + (float)ceil(font.StringWidth(Label()))*2.0f; 404 } 405 //------------------------------------------------------------------------------ 406 void BTextControl::ResizeToPreferred() 407 { 408 float w; 409 float h; 410 GetPreferredSize(&w, &h); 411 BView::ResizeTo(w,h); 412 } 413 //------------------------------------------------------------------------------ 414 void BTextControl::SetFlags(uint32 flags) 415 { 416 if (!fSkipSetFlags) 417 { 418 // If the textview is navigable, set it to not navigable if needed 419 // Else if it is not navigable, set it to navigable if needed 420 if (fText->Flags() & B_NAVIGABLE) 421 { 422 if (!(flags & B_NAVIGABLE)) 423 fText->SetFlags(fText->Flags() & ~B_NAVIGABLE); 424 } 425 else 426 { 427 if (flags & B_NAVIGABLE) 428 fText->SetFlags(fText->Flags() | B_NAVIGABLE); 429 } 430 431 // Don't make this one navigable 432 flags &= ~B_NAVIGABLE; 433 } 434 435 BView::SetFlags(flags); 436 } 437 //------------------------------------------------------------------------------ 438 void BTextControl::MessageReceived(BMessage *msg) 439 { 440 switch(msg->what) 441 { 442 case B_SET_PROPERTY: 443 case B_GET_PROPERTY: 444 // TODO 445 break; 446 default: 447 BControl::MessageReceived(msg); 448 break; 449 } 450 } 451 //------------------------------------------------------------------------------ 452 BHandler *BTextControl::ResolveSpecifier(BMessage *msg, int32 index, 453 BMessage *specifier, int32 form, 454 const char *property) 455 { 456 /* 457 BPropertyInfo propInfo(prop_list); 458 BHandler *target = NULL; 459 460 if (propInfo.FindMatch(message, 0, specifier, what, property) < B_OK) 461 return BControl::ResolveSpecifier(message, index, specifier, what, 462 property); 463 else 464 return this; 465 */ 466 return BControl::ResolveSpecifier(msg, index, specifier, form, property); 467 } 468 //------------------------------------------------------------------------------ 469 status_t BTextControl::GetSupportedSuites(BMessage *data) 470 { 471 return BControl::GetSupportedSuites(data); 472 } 473 //------------------------------------------------------------------------------ 474 void BTextControl::MouseUp(BPoint pt) 475 { 476 BControl::MouseUp(pt); 477 } 478 //------------------------------------------------------------------------------ 479 void BTextControl::MouseMoved(BPoint pt, uint32 code, const BMessage *msg) 480 { 481 BControl::MouseMoved(pt, code, msg); 482 } 483 //------------------------------------------------------------------------------ 484 void BTextControl::DetachedFromWindow() 485 { 486 BControl::DetachedFromWindow(); 487 } 488 //------------------------------------------------------------------------------ 489 void BTextControl::AllAttached() 490 { 491 BControl::AllAttached(); 492 } 493 //------------------------------------------------------------------------------ 494 void BTextControl::AllDetached() 495 { 496 BControl::AllDetached(); 497 } 498 //------------------------------------------------------------------------------ 499 void BTextControl::FrameMoved(BPoint newPosition) 500 { 501 BControl::FrameMoved(newPosition); 502 } 503 //------------------------------------------------------------------------------ 504 void BTextControl::FrameResized(float newWidth, float newHeight) 505 { 506 BControl::FrameResized(newWidth, newHeight); 507 } 508 //------------------------------------------------------------------------------ 509 void BTextControl::WindowActivated(bool active) 510 { 511 if (fText->IsFocus()) 512 Draw(Bounds()); 513 } 514 //------------------------------------------------------------------------------ 515 status_t BTextControl::Perform(perform_code d, void *arg) 516 { 517 return BControl::Perform(d, arg); 518 } 519 //------------------------------------------------------------------------------ 520 void BTextControl::_ReservedTextControl1() {} 521 void BTextControl::_ReservedTextControl2() {} 522 void BTextControl::_ReservedTextControl3() {} 523 void BTextControl::_ReservedTextControl4() {} 524 //------------------------------------------------------------------------------ 525 BTextControl &BTextControl::operator=(const BTextControl&) 526 { 527 return *this; 528 } 529 //------------------------------------------------------------------------------ 530 void BTextControl::CommitValue() 531 { 532 } 533 //------------------------------------------------------------------------------ 534 void BTextControl::InitData(const char *label, const char *initial_text, 535 BMessage *data) 536 { 537 BRect bounds(Bounds()); 538 539 fText = NULL; 540 //fLabel = NULL; 541 fModificationMessage = NULL; 542 fLabelAlign = B_ALIGN_LEFT; 543 fDivider = 0.0f; 544 fPrevWidth = 0; 545 fPrevHeight = 0; 546 //fClean = true; 547 fSkipSetFlags = false; 548 549 int32 flags = 0; 550 551 BFont font(be_bold_font); 552 553 if (!data || !data->HasString("_fname")) 554 flags = 1; 555 556 if (!data || !data->HasFloat("_fflt")) 557 flags |= 2; 558 559 if (flags != 0) 560 SetFont(&font, flags); 561 562 if (label) 563 fDivider = bounds.Width() / 2.0f; 564 565 if (Flags() & B_NAVIGABLE) 566 { 567 fSkipSetFlags = true; 568 SetFlags(Flags() & ~B_NAVIGABLE); 569 fSkipSetFlags = false; 570 } 571 572 if (data) 573 fText = (_BTextInput_*)FindView("_input_"); 574 else 575 { 576 BRect frame(fDivider, bounds.top + 2.0f, bounds.right - 2.0f, 577 bounds.bottom - 2.0f); 578 BRect textRect(frame.OffsetToCopy(0.0f, 0.0f)); 579 580 fText = new _BTextInput_(frame, textRect, 581 B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, B_WILL_DRAW | B_FRAME_EVENTS | 582 B_NAVIGABLE); 583 584 AddChild(fText); 585 586 SetText(initial_text); 587 fText->SetAlignment(B_ALIGN_LEFT); 588 fText->AlignTextRect(); 589 } 590 } 591 //------------------------------------------------------------------------------ 592 593 /* 594 * $Log $ 595 * 596 * $Id $ 597 * 598 */ 599 600