1928ffe6dSJohn Scipione /* 2928ffe6dSJohn Scipione * Copyright 2010-2012 Haiku, Inc. All rights reserved. 3928ffe6dSJohn Scipione * Distributed under the terms of the MIT license. 4928ffe6dSJohn Scipione * 5928ffe6dSJohn Scipione * Authors: 6928ffe6dSJohn Scipione * DarkWyrm <bpmagic@columbus.rr.com> 7928ffe6dSJohn Scipione * John Scipione <jscipione@gmail.com> 8928ffe6dSJohn Scipione */ 9928ffe6dSJohn Scipione 10928ffe6dSJohn Scipione 11928ffe6dSJohn Scipione #include "FakeScrollBar.h" 12928ffe6dSJohn Scipione 13928ffe6dSJohn Scipione #include <Box.h> 14928ffe6dSJohn Scipione #include <ControlLook.h> 15928ffe6dSJohn Scipione #include <Message.h> 16928ffe6dSJohn Scipione #include <ScrollBar.h> 17928ffe6dSJohn Scipione #include <Shape.h> 18928ffe6dSJohn Scipione #include <Size.h> 19928ffe6dSJohn Scipione #include <Window.h> 20928ffe6dSJohn Scipione 21928ffe6dSJohn Scipione 22928ffe6dSJohn Scipione typedef enum { 23928ffe6dSJohn Scipione ARROW_LEFT = 0, 24928ffe6dSJohn Scipione ARROW_RIGHT, 25928ffe6dSJohn Scipione ARROW_UP, 26928ffe6dSJohn Scipione ARROW_DOWN, 27928ffe6dSJohn Scipione ARROW_NONE 28928ffe6dSJohn Scipione } arrow_direction; 29928ffe6dSJohn Scipione 30928ffe6dSJohn Scipione 31928ffe6dSJohn Scipione FakeScrollBar::FakeScrollBar(bool drawArrows, bool doubleArrows, 32928ffe6dSJohn Scipione int32 knobStyle, BMessage* message) 33928ffe6dSJohn Scipione : 3412a7abb6SJohn Scipione BControl("FakeScrollBar", NULL, message, B_WILL_DRAW | B_NAVIGABLE), 35928ffe6dSJohn Scipione fDrawArrows(drawArrows), 36928ffe6dSJohn Scipione fDoubleArrows(doubleArrows), 37928ffe6dSJohn Scipione fKnobStyle(knobStyle) 38928ffe6dSJohn Scipione { 39928ffe6dSJohn Scipione SetExplicitMinSize(BSize(160, 20)); 40928ffe6dSJohn Scipione SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 20)); 41928ffe6dSJohn Scipione } 42928ffe6dSJohn Scipione 43928ffe6dSJohn Scipione 44928ffe6dSJohn Scipione FakeScrollBar::~FakeScrollBar(void) 45928ffe6dSJohn Scipione { 46928ffe6dSJohn Scipione } 47928ffe6dSJohn Scipione 48928ffe6dSJohn Scipione 49928ffe6dSJohn Scipione void 50928ffe6dSJohn Scipione FakeScrollBar::Draw(BRect updateRect) 51928ffe6dSJohn Scipione { 52928ffe6dSJohn Scipione BRect bounds = Bounds(); 53928ffe6dSJohn Scipione 54928ffe6dSJohn Scipione rgb_color normal = ui_color(B_PANEL_BACKGROUND_COLOR); 55928ffe6dSJohn Scipione 5612a7abb6SJohn Scipione if (IsFocus()) { 5712a7abb6SJohn Scipione // draw the focus indicator 5812a7abb6SJohn Scipione SetHighColor(ui_color(B_NAVIGATION_BASE_COLOR)); 5912a7abb6SJohn Scipione StrokeRect(bounds); 6012a7abb6SJohn Scipione bounds.InsetBy(1.0, 1.0); 6112a7abb6SJohn Scipione 6212a7abb6SJohn Scipione // Draw the selected border (1px) 63928ffe6dSJohn Scipione if (Value() == B_CONTROL_ON) 64928ffe6dSJohn Scipione SetHighColor(ui_color(B_CONTROL_MARK_COLOR)); 65928ffe6dSJohn Scipione else 66928ffe6dSJohn Scipione SetHighColor(normal); 67928ffe6dSJohn Scipione 6812a7abb6SJohn Scipione StrokeRect(bounds); 6912a7abb6SJohn Scipione bounds.InsetBy(1.0, 1.0); 7012a7abb6SJohn Scipione } else { 71928ffe6dSJohn Scipione // Draw the selected border (2px) 7212a7abb6SJohn Scipione if (Value() == B_CONTROL_ON) 7312a7abb6SJohn Scipione SetHighColor(ui_color(B_CONTROL_MARK_COLOR)); 7412a7abb6SJohn Scipione else 7512a7abb6SJohn Scipione SetHighColor(normal); 7612a7abb6SJohn Scipione 77928ffe6dSJohn Scipione StrokeRect(bounds); 78928ffe6dSJohn Scipione bounds.InsetBy(1.0, 1.0); 79928ffe6dSJohn Scipione StrokeRect(bounds); 80928ffe6dSJohn Scipione bounds.InsetBy(1.0, 1.0); 8112a7abb6SJohn Scipione } 82928ffe6dSJohn Scipione 83928ffe6dSJohn Scipione // draw a gap (1px) 84928ffe6dSJohn Scipione SetHighColor(normal); 85928ffe6dSJohn Scipione StrokeRect(bounds); 86928ffe6dSJohn Scipione bounds.InsetBy(1.0, 1.0); 87928ffe6dSJohn Scipione 88928ffe6dSJohn Scipione // draw a border around control (1px) 89928ffe6dSJohn Scipione SetHighColor(tint_color(normal, B_DARKEN_1_TINT)); 90928ffe6dSJohn Scipione StrokeRect(bounds); 91928ffe6dSJohn Scipione bounds.InsetBy(1.0, 1.0); 92928ffe6dSJohn Scipione 93928ffe6dSJohn Scipione BRect thumbBG = bounds; 94928ffe6dSJohn Scipione BRect bgRect = bounds; 95928ffe6dSJohn Scipione 96928ffe6dSJohn Scipione if (fDrawArrows) { 97928ffe6dSJohn Scipione // draw arrows 98928ffe6dSJohn Scipione SetDrawingMode(B_OP_OVER); 99928ffe6dSJohn Scipione 100928ffe6dSJohn Scipione BRect buttonFrame(bounds.left, bounds.top, 101928ffe6dSJohn Scipione bounds.left + bounds.Height(), bounds.bottom); 102928ffe6dSJohn Scipione 103928ffe6dSJohn Scipione _DrawArrowButton(ARROW_LEFT, fDoubleArrows, buttonFrame, updateRect); 104928ffe6dSJohn Scipione 105928ffe6dSJohn Scipione if (fDoubleArrows) { 106928ffe6dSJohn Scipione buttonFrame.OffsetBy(bounds.Height() + 1, 0.0); 107928ffe6dSJohn Scipione _DrawArrowButton(ARROW_RIGHT, fDoubleArrows, buttonFrame, 108928ffe6dSJohn Scipione updateRect); 109928ffe6dSJohn Scipione 110928ffe6dSJohn Scipione buttonFrame.OffsetTo(bounds.right - ((bounds.Height() * 2) + 1), 111928ffe6dSJohn Scipione bounds.top); 112928ffe6dSJohn Scipione _DrawArrowButton(ARROW_LEFT, fDoubleArrows, buttonFrame, 113928ffe6dSJohn Scipione updateRect); 114928ffe6dSJohn Scipione 115928ffe6dSJohn Scipione thumbBG.left += bounds.Height() * 2 + 2; 116928ffe6dSJohn Scipione thumbBG.right -= bounds.Height() * 2 + 2; 117928ffe6dSJohn Scipione } else { 118928ffe6dSJohn Scipione thumbBG.left += bounds.Height() + 1; 119928ffe6dSJohn Scipione thumbBG.right -= bounds.Height() + 1; 120928ffe6dSJohn Scipione } 121928ffe6dSJohn Scipione 122928ffe6dSJohn Scipione buttonFrame.OffsetTo(bounds.right - bounds.Height(), bounds.top); 123928ffe6dSJohn Scipione _DrawArrowButton(ARROW_RIGHT, fDoubleArrows, buttonFrame, updateRect); 124928ffe6dSJohn Scipione 125928ffe6dSJohn Scipione SetDrawingMode(B_OP_COPY); 126928ffe6dSJohn Scipione 127928ffe6dSJohn Scipione bgRect = bounds.InsetByCopy(48, 0); 128928ffe6dSJohn Scipione } else 129928ffe6dSJohn Scipione bgRect = bounds.InsetByCopy(16, 0); 130928ffe6dSJohn Scipione 131928ffe6dSJohn Scipione // fill background besides the thumb 132928ffe6dSJohn Scipione BRect leftOfThumb(thumbBG.left, thumbBG.top, bgRect.left - 1, 133928ffe6dSJohn Scipione thumbBG.bottom); 134928ffe6dSJohn Scipione BRect rightOfThumb(bgRect.right + 1, thumbBG.top, thumbBG.right, 135928ffe6dSJohn Scipione thumbBG.bottom); 136928ffe6dSJohn Scipione 137928ffe6dSJohn Scipione be_control_look->DrawScrollBarBackground(this, leftOfThumb, 138928ffe6dSJohn Scipione rightOfThumb, updateRect, normal, 0, B_HORIZONTAL); 139928ffe6dSJohn Scipione 140928ffe6dSJohn Scipione // Draw scroll thumb 141928ffe6dSJohn Scipione 142928ffe6dSJohn Scipione // fill the clickable surface of the thumb 143928ffe6dSJohn Scipione be_control_look->DrawButtonBackground(this, bgRect, updateRect, 144928ffe6dSJohn Scipione normal, 0, BControlLook::B_ALL_BORDERS, B_HORIZONTAL); 145928ffe6dSJohn Scipione 146*dfa8cf8cSJohn Scipione if (fKnobStyle == B_KNOB_STYLE_NONE) 147928ffe6dSJohn Scipione return; 148928ffe6dSJohn Scipione 149928ffe6dSJohn Scipione // draw the scrollbar thumb knobs 150*dfa8cf8cSJohn Scipione bool square = fKnobStyle == B_KNOB_STYLE_DOTS; 151928ffe6dSJohn Scipione int32 hextent = 0; 152928ffe6dSJohn Scipione int32 vextent = 0; 153928ffe6dSJohn Scipione 154928ffe6dSJohn Scipione if (square) { 155928ffe6dSJohn Scipione hextent = 2; 156928ffe6dSJohn Scipione vextent = 2; 157928ffe6dSJohn Scipione } else { 158928ffe6dSJohn Scipione hextent = 1; 159928ffe6dSJohn Scipione vextent = 3; 160928ffe6dSJohn Scipione } 161928ffe6dSJohn Scipione 162928ffe6dSJohn Scipione float hmiddle = bgRect.Width() / 2; 163928ffe6dSJohn Scipione float vmiddle = bgRect.Height() / 2; 164928ffe6dSJohn Scipione 165928ffe6dSJohn Scipione BRect middleKnob = BRect(bgRect.left + hmiddle - hextent, 166928ffe6dSJohn Scipione bgRect.top + vmiddle - vextent, 167928ffe6dSJohn Scipione bgRect.left + hmiddle + hextent, 168928ffe6dSJohn Scipione bgRect.top + vmiddle + vextent); 169928ffe6dSJohn Scipione 170928ffe6dSJohn Scipione BRect leftKnob = middleKnob.OffsetByCopy(hextent * -4, 0); 171928ffe6dSJohn Scipione if (leftKnob.left > bgRect.left + hextent) { 172928ffe6dSJohn Scipione be_control_look->DrawButtonBackground(this, leftKnob, updateRect, 173928ffe6dSJohn Scipione normal, 0, BControlLook::B_ALL_BORDERS, B_HORIZONTAL); 174928ffe6dSJohn Scipione } 175928ffe6dSJohn Scipione 176928ffe6dSJohn Scipione BRect rightKnob = middleKnob.OffsetByCopy(hextent * 4, 0); 177928ffe6dSJohn Scipione if (rightKnob.right < bgRect.right - hextent) { 178928ffe6dSJohn Scipione be_control_look->DrawButtonBackground(this, rightKnob, updateRect, 179928ffe6dSJohn Scipione normal, 0, BControlLook::B_ALL_BORDERS, B_HORIZONTAL); 180928ffe6dSJohn Scipione } 181928ffe6dSJohn Scipione 182928ffe6dSJohn Scipione // draw middle knob last because it modifies middleKnob 183928ffe6dSJohn Scipione be_control_look->DrawButtonBackground(this, middleKnob, updateRect, 184928ffe6dSJohn Scipione normal, 0, BControlLook::B_ALL_BORDERS, B_HORIZONTAL); 185928ffe6dSJohn Scipione } 186928ffe6dSJohn Scipione 187928ffe6dSJohn Scipione 188928ffe6dSJohn Scipione void 189928ffe6dSJohn Scipione FakeScrollBar::MouseDown(BPoint point) 190928ffe6dSJohn Scipione { 191928ffe6dSJohn Scipione BControl::MouseDown(point); 192928ffe6dSJohn Scipione } 193928ffe6dSJohn Scipione 194928ffe6dSJohn Scipione 195928ffe6dSJohn Scipione void 196928ffe6dSJohn Scipione FakeScrollBar::MouseMoved(BPoint point, uint32 transit, 197928ffe6dSJohn Scipione const BMessage* message) 198928ffe6dSJohn Scipione { 199928ffe6dSJohn Scipione BControl::MouseMoved(point, transit, message); 200928ffe6dSJohn Scipione } 201928ffe6dSJohn Scipione 202928ffe6dSJohn Scipione 203928ffe6dSJohn Scipione void 204928ffe6dSJohn Scipione FakeScrollBar::MouseUp(BPoint point) 205928ffe6dSJohn Scipione { 206928ffe6dSJohn Scipione SetValue(B_CONTROL_ON); 207928ffe6dSJohn Scipione Invoke(); 208928ffe6dSJohn Scipione 209928ffe6dSJohn Scipione Invalidate(); 210928ffe6dSJohn Scipione 211928ffe6dSJohn Scipione BControl::MouseUp(point); 212928ffe6dSJohn Scipione } 213928ffe6dSJohn Scipione 214928ffe6dSJohn Scipione 215928ffe6dSJohn Scipione void 216928ffe6dSJohn Scipione FakeScrollBar::SetValue(int32 value) 217928ffe6dSJohn Scipione { 218928ffe6dSJohn Scipione if (value != Value()) { 219928ffe6dSJohn Scipione BControl::SetValueNoUpdate(value); 220928ffe6dSJohn Scipione Invalidate(); 221928ffe6dSJohn Scipione } 222928ffe6dSJohn Scipione 223928ffe6dSJohn Scipione if (!value) 224928ffe6dSJohn Scipione return; 225928ffe6dSJohn Scipione 226928ffe6dSJohn Scipione BView* parent = Parent(); 227928ffe6dSJohn Scipione BView* child = NULL; 228928ffe6dSJohn Scipione 229928ffe6dSJohn Scipione if (parent != NULL) { 230928ffe6dSJohn Scipione // If the parent is a BBox, the group parent is the parent of the BBox 231928ffe6dSJohn Scipione BBox* box = dynamic_cast<BBox*>(parent); 232928ffe6dSJohn Scipione 233928ffe6dSJohn Scipione if (box && box->LabelView() == this) 234928ffe6dSJohn Scipione parent = box->Parent(); 235928ffe6dSJohn Scipione 236928ffe6dSJohn Scipione if (parent != NULL) { 237928ffe6dSJohn Scipione BBox* box = dynamic_cast<BBox*>(parent); 238928ffe6dSJohn Scipione 239928ffe6dSJohn Scipione // If the parent is a BBox, skip the label if there is one 240928ffe6dSJohn Scipione if (box && box->LabelView()) 241928ffe6dSJohn Scipione child = parent->ChildAt(1); 242928ffe6dSJohn Scipione else 243928ffe6dSJohn Scipione child = parent->ChildAt(0); 244928ffe6dSJohn Scipione } else 245928ffe6dSJohn Scipione child = Window()->ChildAt(0); 246928ffe6dSJohn Scipione } else if (Window()) 247928ffe6dSJohn Scipione child = Window()->ChildAt(0); 248928ffe6dSJohn Scipione 249928ffe6dSJohn Scipione while (child) { 250928ffe6dSJohn Scipione FakeScrollBar* scrollbar = dynamic_cast<FakeScrollBar*>(child); 251928ffe6dSJohn Scipione 252928ffe6dSJohn Scipione if (scrollbar != NULL && (scrollbar != this)) 253928ffe6dSJohn Scipione scrollbar->SetValue(B_CONTROL_OFF); 254928ffe6dSJohn Scipione else { 255928ffe6dSJohn Scipione // If the child is a BBox, check if the label is a scrollbarbutton 256928ffe6dSJohn Scipione BBox* box = dynamic_cast<BBox*>(child); 257928ffe6dSJohn Scipione 258928ffe6dSJohn Scipione if (box && box->LabelView()) { 259928ffe6dSJohn Scipione scrollbar = dynamic_cast<FakeScrollBar*>(box->LabelView()); 260928ffe6dSJohn Scipione 261928ffe6dSJohn Scipione if (scrollbar != NULL && (scrollbar != this)) 262928ffe6dSJohn Scipione scrollbar->SetValue(B_CONTROL_OFF); 263928ffe6dSJohn Scipione } 264928ffe6dSJohn Scipione } 265928ffe6dSJohn Scipione 266928ffe6dSJohn Scipione child = child->NextSibling(); 267928ffe6dSJohn Scipione } 268928ffe6dSJohn Scipione 269928ffe6dSJohn Scipione //ASSERT(Value() == B_CONTROL_ON); 270928ffe6dSJohn Scipione } 271928ffe6dSJohn Scipione 272928ffe6dSJohn Scipione 273928ffe6dSJohn Scipione // #pragma mark - 274928ffe6dSJohn Scipione 275928ffe6dSJohn Scipione 276928ffe6dSJohn Scipione void 277928ffe6dSJohn Scipione FakeScrollBar::SetDoubleArrows(bool doublearrows) 278928ffe6dSJohn Scipione { 279928ffe6dSJohn Scipione fDoubleArrows = doublearrows; 280928ffe6dSJohn Scipione Invalidate(); 281928ffe6dSJohn Scipione } 282928ffe6dSJohn Scipione 283928ffe6dSJohn Scipione 284928ffe6dSJohn Scipione void 285928ffe6dSJohn Scipione FakeScrollBar::SetKnobStyle(uint32 style) 286928ffe6dSJohn Scipione { 287928ffe6dSJohn Scipione fKnobStyle = style; 288928ffe6dSJohn Scipione Invalidate(); 289928ffe6dSJohn Scipione } 290928ffe6dSJohn Scipione 291928ffe6dSJohn Scipione 292928ffe6dSJohn Scipione void 293928ffe6dSJohn Scipione FakeScrollBar::SetFromScrollBarInfo(const scroll_bar_info &info) 294928ffe6dSJohn Scipione { 295928ffe6dSJohn Scipione fDoubleArrows = info.double_arrows; 296928ffe6dSJohn Scipione fKnobStyle = info.knob; 297928ffe6dSJohn Scipione Invalidate(); 298928ffe6dSJohn Scipione } 299928ffe6dSJohn Scipione 300928ffe6dSJohn Scipione 301928ffe6dSJohn Scipione // #pragma mark - 302928ffe6dSJohn Scipione 303928ffe6dSJohn Scipione 304928ffe6dSJohn Scipione void 305928ffe6dSJohn Scipione FakeScrollBar::_DrawArrowButton(int32 direction, bool doubleArrows, BRect r, 306928ffe6dSJohn Scipione const BRect& updateRect) 307928ffe6dSJohn Scipione { 308928ffe6dSJohn Scipione if (!updateRect.Intersects(r)) 309928ffe6dSJohn Scipione return; 310928ffe6dSJohn Scipione 311928ffe6dSJohn Scipione rgb_color c = ui_color(B_PANEL_BACKGROUND_COLOR); 312928ffe6dSJohn Scipione rgb_color light = tint_color(c, B_LIGHTEN_MAX_TINT); 313928ffe6dSJohn Scipione rgb_color dark = tint_color(c, B_DARKEN_1_TINT); 314928ffe6dSJohn Scipione rgb_color darker = tint_color(c, B_DARKEN_2_TINT); 315928ffe6dSJohn Scipione rgb_color normal = c; 316928ffe6dSJohn Scipione rgb_color arrow = tint_color(c, 317928ffe6dSJohn Scipione (B_DARKEN_MAX_TINT + B_DARKEN_4_TINT) / 2.0); 318928ffe6dSJohn Scipione 319928ffe6dSJohn Scipione BPoint tri1, tri2, tri3; 320928ffe6dSJohn Scipione float hInset = r.Width() / 3; 321928ffe6dSJohn Scipione float vInset = r.Height() / 3; 322928ffe6dSJohn Scipione r.InsetBy(hInset, vInset); 323928ffe6dSJohn Scipione 324928ffe6dSJohn Scipione switch (direction) { 325928ffe6dSJohn Scipione case ARROW_LEFT: 326928ffe6dSJohn Scipione tri1.Set(r.right, r.top); 327928ffe6dSJohn Scipione tri2.Set(r.right - r.Width() / 1.33, (r.top + r.bottom + 1) / 2); 328928ffe6dSJohn Scipione tri3.Set(r.right, r.bottom + 1); 329928ffe6dSJohn Scipione break; 330928ffe6dSJohn Scipione 331928ffe6dSJohn Scipione case ARROW_RIGHT: 332928ffe6dSJohn Scipione tri1.Set(r.left, r.bottom + 1); 333928ffe6dSJohn Scipione tri2.Set(r.left + r.Width() / 1.33, (r.top + r.bottom + 1) / 2); 334928ffe6dSJohn Scipione tri3.Set(r.left, r.top); 335928ffe6dSJohn Scipione break; 336928ffe6dSJohn Scipione 337928ffe6dSJohn Scipione case ARROW_UP: 338928ffe6dSJohn Scipione tri1.Set(r.left, r.bottom); 339928ffe6dSJohn Scipione tri2.Set((r.left + r.right + 1) / 2, r.bottom - r.Height() / 1.33); 340928ffe6dSJohn Scipione tri3.Set(r.right + 1, r.bottom); 341928ffe6dSJohn Scipione break; 342928ffe6dSJohn Scipione 343928ffe6dSJohn Scipione default: 344928ffe6dSJohn Scipione tri1.Set(r.left, r.top); 345928ffe6dSJohn Scipione tri2.Set((r.left + r.right + 1) / 2, r.top + r.Height() / 1.33); 346928ffe6dSJohn Scipione tri3.Set(r.right + 1, r.top); 347928ffe6dSJohn Scipione break; 348928ffe6dSJohn Scipione } 349928ffe6dSJohn Scipione 350928ffe6dSJohn Scipione r.InsetBy(-(hInset - 1), -(vInset - 1)); 351928ffe6dSJohn Scipione BRect temp(r.InsetByCopy(-1, -1)); 352928ffe6dSJohn Scipione be_control_look->DrawButtonBackground(this, temp, updateRect, 353928ffe6dSJohn Scipione normal, 0, BControlLook::B_ALL_BORDERS, B_HORIZONTAL); 354928ffe6dSJohn Scipione 355928ffe6dSJohn Scipione BShape arrowShape; 356928ffe6dSJohn Scipione arrowShape.MoveTo(tri1); 357928ffe6dSJohn Scipione arrowShape.LineTo(tri2); 358928ffe6dSJohn Scipione arrowShape.LineTo(tri3); 359928ffe6dSJohn Scipione 360928ffe6dSJohn Scipione SetHighColor(arrow); 361928ffe6dSJohn Scipione SetPenSize(ceilf(hInset / 2.0)); 362928ffe6dSJohn Scipione StrokeShape(&arrowShape); 363928ffe6dSJohn Scipione SetPenSize(1.0); 364928ffe6dSJohn Scipione } 365