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: CheckBox.cpp 23 // Author: Marc Flerackers (mflerackers@androme.be) 24 // Description: BCheckBox displays an on/off control. 25 //------------------------------------------------------------------------------ 26 #include <CheckBox.h> 27 #include <Window.h> 28 29 30 BCheckBox::BCheckBox(BRect frame, const char *name, const char *label, 31 BMessage *message, uint32 resizingMode, uint32 flags) 32 : BControl(frame, name, label, message, resizingMode, flags), 33 fOutlined(false) 34 { 35 // Resize to minimum height if needed 36 font_height fontHeight; 37 GetFontHeight(&fontHeight); 38 float minHeight = (float)ceil(6.0f + fontHeight.ascent + fontHeight.descent); 39 if (Bounds().Height() < minHeight) 40 ResizeTo(Bounds().Width(), minHeight); 41 } 42 43 44 BCheckBox::~BCheckBox() 45 { 46 47 } 48 49 50 BCheckBox::BCheckBox(BMessage *archive) 51 : BControl(archive), 52 fOutlined(false) 53 { 54 } 55 56 57 BArchivable * 58 BCheckBox::Instantiate(BMessage *archive) 59 { 60 if (validate_instantiation(archive, "BCheckBox")) 61 return new BCheckBox(archive); 62 else 63 return NULL; 64 } 65 66 67 status_t 68 BCheckBox::Archive(BMessage *archive, bool deep) const 69 { 70 return BControl::Archive(archive,deep); 71 } 72 73 74 void 75 BCheckBox::Draw(BRect updateRect) 76 { 77 font_height fontHeight; 78 GetFontHeight(&fontHeight); 79 80 // If the focus is changing, just redraw the focus indicator 81 if (IsFocusChanging()) { 82 float x = (float)ceil(10.0f + fontHeight.ascent); 83 float y = 5.0f + (float)ceil(fontHeight.ascent); 84 85 if (IsFocus()) 86 SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); 87 else 88 SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 89 90 StrokeLine(BPoint(x, y), BPoint(x + StringWidth(Label()), y)); 91 92 return; 93 } 94 95 rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR), 96 lighten1 = tint_color(no_tint, B_LIGHTEN_1_TINT), 97 lightenmax = tint_color(no_tint, B_LIGHTEN_MAX_TINT), 98 darken1 = tint_color(no_tint, B_DARKEN_1_TINT), 99 darken2 = tint_color(no_tint, B_DARKEN_2_TINT), 100 darken3 = tint_color(no_tint, B_DARKEN_3_TINT), 101 darken4 = tint_color(no_tint, B_DARKEN_4_TINT), 102 darkenmax = tint_color(no_tint, B_DARKEN_MAX_TINT); 103 104 BRect rect = _CheckBoxFrame(); 105 106 if (IsEnabled()) { 107 // Filling 108 SetHighColor(lightenmax); 109 FillRect(rect); 110 111 // Box 112 if (fOutlined) { 113 SetHighColor(darken3); 114 StrokeRect(rect); 115 116 rect.InsetBy(1,1); 117 118 BeginLineArray(6); 119 120 AddLine(BPoint(rect.left, rect.bottom), 121 BPoint(rect.left, rect.top), darken2); 122 AddLine(BPoint(rect.left, rect.top), 123 BPoint(rect.right, rect.top), darken2); 124 AddLine(BPoint(rect.left, rect.bottom), 125 BPoint(rect.right, rect.bottom), darken4); 126 AddLine(BPoint(rect.right, rect.bottom), 127 BPoint(rect.right, rect.top), darken4); 128 129 EndLineArray(); 130 } else { 131 BeginLineArray(6); 132 133 AddLine(BPoint(rect.left, rect.bottom), 134 BPoint(rect.left, rect.top), darken1); 135 AddLine(BPoint(rect.left, rect.top), 136 BPoint(rect.right, rect.top), darken1); 137 rect.InsetBy(1,1); 138 AddLine(BPoint(rect.left, rect.bottom), 139 BPoint(rect.left, rect.top), darken4); 140 AddLine(BPoint(rect.left, rect.top), 141 BPoint(rect.right, rect.top), darken4); 142 AddLine(BPoint(rect.left + 1.0f, rect.bottom), 143 BPoint(rect.right, rect.bottom), no_tint); 144 AddLine(BPoint(rect.right, rect.bottom), 145 BPoint(rect.right, rect.top + 1.0f), no_tint); 146 147 EndLineArray(); 148 } 149 150 // Checkmark 151 if (Value() == B_CONTROL_ON) { 152 rect.InsetBy(2,2); 153 154 SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); 155 SetPenSize(2); 156 // Yes, Haiku is differnt because of the anti-aliasing 157 SetDrawingMode(B_OP_OVER); 158 StrokeLine(BPoint(rect.left, rect.top), 159 BPoint(rect.right, rect.bottom)); 160 StrokeLine(BPoint(rect.left, rect.bottom), 161 BPoint(rect.right, rect.top)); 162 SetPenSize(1); 163 SetDrawingMode(B_OP_COPY); 164 } 165 166 // Label 167 SetHighColor(darkenmax); 168 DrawString(Label(), BPoint((float)ceil(10.0f + fontHeight.ascent), 169 3.0f + (float)ceil(fontHeight.ascent))); 170 171 // Focus 172 if (IsFocus()) { 173 float x = (float)ceil(10.0f + fontHeight.ascent); 174 float y = 5.0f + (float)ceil(fontHeight.ascent); 175 176 SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); 177 StrokeLine(BPoint(x, y), BPoint(x + StringWidth(Label()), y)); 178 } 179 } else { 180 // Filling 181 SetHighColor(lighten1); 182 FillRect(rect); 183 184 // Box 185 BeginLineArray(6); 186 187 AddLine(BPoint(rect.left, rect.bottom), 188 BPoint(rect.left, rect.top), no_tint); 189 AddLine(BPoint(rect.left, rect.top), 190 BPoint(rect.right, rect.top), no_tint); 191 rect.InsetBy(1,1); 192 AddLine(BPoint(rect.left, rect.bottom), 193 BPoint(rect.left, rect.top), darken2); 194 AddLine(BPoint(rect.left, rect.top), 195 BPoint(rect.right, rect.top), darken2); 196 AddLine(BPoint(rect.left + 1.0f, rect.bottom), 197 BPoint(rect.right, rect.bottom), darken1); 198 AddLine(BPoint(rect.right, rect.bottom), 199 BPoint(rect.right, rect.top + 1.0f), darken1); 200 201 EndLineArray(); 202 203 // Checkmark 204 if (Value() == B_CONTROL_ON) { 205 rect.InsetBy(2, 2); 206 207 SetHighColor(tint_color(ui_color(B_KEYBOARD_NAVIGATION_COLOR), 208 B_DISABLED_MARK_TINT)); 209 SetPenSize(2); 210 // Yes, Haiku is differnt because of the anti-aliasing 211 SetDrawingMode(B_OP_OVER); 212 StrokeLine(BPoint(rect.left, rect.top), 213 BPoint(rect.right, rect.bottom)); 214 StrokeLine(BPoint(rect.left, rect.bottom), 215 BPoint(rect.right, rect.top)); 216 SetPenSize(1); 217 SetDrawingMode(B_OP_COPY); 218 } 219 220 // Label 221 SetHighColor(tint_color(no_tint, B_DISABLED_LABEL_TINT)); 222 DrawString(Label(), BPoint((float)ceil(10.0f + fontHeight.ascent), 223 3.0f + (float)ceil(fontHeight.ascent))); 224 } 225 } 226 227 228 void 229 BCheckBox::AttachedToWindow() 230 { 231 BControl::AttachedToWindow(); 232 } 233 234 235 void 236 BCheckBox::MouseDown(BPoint point) 237 { 238 if (!IsEnabled()) 239 return; 240 241 fOutlined = true; 242 243 if (Window()->Flags() & B_ASYNCHRONOUS_CONTROLS) { 244 Invalidate(); 245 SetTracking(true); 246 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); 247 } else { 248 BRect bounds = Bounds(); 249 uint32 buttons; 250 251 Draw(Bounds()); 252 Flush(); 253 254 do { 255 snooze(40000); 256 257 GetMouse(&point, &buttons, true); 258 259 bool inside = bounds.Contains(point); 260 261 if (fOutlined != inside) { 262 fOutlined = inside; 263 Draw(Bounds()); 264 Flush(); 265 } 266 } while (buttons != 0); 267 268 if (fOutlined) { 269 fOutlined = false; 270 SetValue(!Value()); 271 Invoke(); 272 } else { 273 Draw(Bounds()); 274 Flush(); 275 } 276 } 277 } 278 279 280 void 281 BCheckBox::MessageReceived(BMessage *message) 282 { 283 BControl::MessageReceived(message); 284 } 285 286 287 void 288 BCheckBox::WindowActivated(bool active) 289 { 290 BControl::WindowActivated(active); 291 } 292 293 294 void 295 BCheckBox::KeyDown(const char *bytes, int32 numBytes) 296 { 297 BControl::KeyDown(bytes, numBytes); 298 } 299 300 301 void 302 BCheckBox::MouseUp(BPoint point) 303 { 304 if (!IsTracking()) 305 return; 306 307 bool inside = Bounds().Contains(point); 308 309 if (fOutlined != inside) { 310 fOutlined = inside; 311 Invalidate(); 312 } 313 314 if (fOutlined) { 315 fOutlined = false; 316 SetValue(!Value()); 317 Invoke(); 318 } else { 319 Invalidate(); 320 } 321 322 SetTracking(false); 323 } 324 325 326 void 327 BCheckBox::MouseMoved(BPoint point, uint32 transit, 328 const BMessage *message) 329 { 330 if (!IsTracking()) 331 return; 332 333 bool inside = Bounds().Contains(point); 334 335 if (fOutlined != inside) { 336 fOutlined = inside; 337 Invalidate(); 338 } 339 } 340 341 342 void 343 BCheckBox::DetachedFromWindow() 344 { 345 BControl::DetachedFromWindow(); 346 } 347 348 349 void 350 BCheckBox::SetValue(int32 value) 351 { 352 if (value != Value()) { 353 BControl::SetValue(value); 354 Invalidate(_CheckBoxFrame()); 355 } 356 } 357 358 359 void 360 BCheckBox::GetPreferredSize(float* _width, float* _height) 361 { 362 font_height fontHeight; 363 GetFontHeight(&fontHeight); 364 365 if (_width) { 366 float width = 12.0f + fontHeight.ascent; 367 368 if (Label()) 369 width += StringWidth(Label()); 370 371 *_width = (float)ceil(width); 372 } 373 374 if (_height) 375 *_height = (float)ceil(6.0f + fontHeight.ascent + fontHeight.descent); 376 } 377 378 379 void 380 BCheckBox::ResizeToPreferred() 381 { 382 BControl::ResizeToPreferred(); 383 } 384 385 386 status_t 387 BCheckBox::Invoke(BMessage *message) 388 { 389 return BControl::Invoke(message); 390 } 391 392 393 void 394 BCheckBox::FrameMoved(BPoint newLocation) 395 { 396 BControl::FrameMoved(newLocation); 397 } 398 399 400 void 401 BCheckBox::FrameResized(float width, float height) 402 { 403 BControl::FrameResized(width, height); 404 } 405 406 407 BHandler * 408 BCheckBox::ResolveSpecifier(BMessage *message, int32 index, 409 BMessage *specifier, int32 what, 410 const char *property) 411 { 412 return BControl::ResolveSpecifier(message, index, specifier, what, property); 413 } 414 415 416 status_t 417 BCheckBox::GetSupportedSuites(BMessage *message) 418 { 419 return BControl::GetSupportedSuites(message); 420 } 421 422 423 void 424 BCheckBox::MakeFocus(bool focused) 425 { 426 BControl::MakeFocus(focused); 427 } 428 429 430 void 431 BCheckBox::AllAttached() 432 { 433 BControl::AllAttached(); 434 } 435 436 437 void 438 BCheckBox::AllDetached() 439 { 440 BControl::AllDetached(); 441 } 442 443 444 status_t 445 BCheckBox::Perform(perform_code d, void *arg) 446 { 447 return BControl::Perform(d, arg); 448 } 449 450 451 void BCheckBox::_ReservedCheckBox1() {} 452 void BCheckBox::_ReservedCheckBox2() {} 453 void BCheckBox::_ReservedCheckBox3() {} 454 455 456 BCheckBox & 457 BCheckBox::operator=(const BCheckBox &) 458 { 459 return *this; 460 } 461 462 // _CheckBoxFrame 463 BRect 464 BCheckBox::_CheckBoxFrame() const 465 { 466 font_height fh; 467 GetFontHeight(&fh); 468 469 return BRect(1.0f, 3.0f, ceilf(3.0f + fh.ascent), ceilf(5.0f + fh.ascent)); 470 } 471