1/* 2 * Copyright 2006, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus <superstippi@gmx.de> 7 */ 8 9#include "IconOptionsControl.h" 10 11#include <stdio.h> 12 13#include <Window.h> 14 15#include "IconButton.h" 16 17#define LABEL_DIST 8.0 18 19// constructor 20IconOptionsControl::IconOptionsControl(const char* name, 21 const char* label, 22 BMessage* message, 23 BHandler* target) 24 : MView(), 25 BControl(BRect(0.0, 0.0, 10.0, 10.0), name, label, message, 26 B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS), 27 fTargetCache(target) 28{ 29 if (Label()) { 30 labelwidth = StringWidth(Label()) + LABEL_DIST; 31 } else { 32 labelwidth = 0.0; 33 } 34} 35 36// destructor 37IconOptionsControl::~IconOptionsControl() 38{ 39} 40 41// layoutprefs 42minimax 43IconOptionsControl::layoutprefs() 44{ 45 // sanity checks 46 if (rolemodel) 47 labelwidth = rolemodel->LabelWidth(); 48 if (labelwidth < LabelWidth()) 49 labelwidth = LabelWidth(); 50 51 mpm.mini.x = 0.0 + labelwidth + 5.0; 52 mpm.mini.y = 0.0; 53 54 for (int32 i = 0; IconButton* button = _FindIcon(i); i++) { 55 minimax childPrefs = button->layoutprefs(); 56 mpm.mini.x += childPrefs.mini.x + 1; 57 if (mpm.mini.y < childPrefs.mini.y + 1) 58 mpm.mini.y = childPrefs.mini.y + 1; 59 } 60 61 mpm.maxi.x = mpm.mini.x; 62 mpm.maxi.y = mpm.mini.y; 63 64 mpm.weight = 1.0; 65 66 return mpm; 67} 68 69// layout 70BRect 71IconOptionsControl::layout(BRect frame) 72{ 73 if (frame.Width() < mpm.mini.x + 1) 74 frame.right = frame.left + mpm.mini.x + 1; 75 76 MoveTo(frame.LeftTop()); 77 ResizeTo(frame.Width(), frame.Height()); 78 79 return Frame(); 80} 81 82// LabelWidth 83float 84IconOptionsControl::LabelWidth() 85{ 86 float width = ceilf(StringWidth(Label())); 87 if (width > 0.0) 88 width += LABEL_DIST; 89 return width; 90} 91 92// SetLabel 93void 94IconOptionsControl::SetLabel(const char* label) 95{ 96 BControl::SetLabel(label); 97 float width = LabelWidth(); 98 if (rolemodel) 99 labelwidth = rolemodel->LabelWidth() > labelwidth ? 100 rolemodel->LabelWidth() : labelwidth; 101 102 labelwidth = width > labelwidth ? width : labelwidth; 103 104 _TriggerRelayout(); 105} 106 107// AttachedToWindow 108void 109IconOptionsControl::AttachedToWindow() 110{ 111 BControl::AttachedToWindow(); 112 113 SetViewColor(B_TRANSPARENT_32_BIT); 114 SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 115} 116 117// AllAttached 118void 119IconOptionsControl::AllAttached() 120{ 121 for (int32 i = 0; IconButton* button = _FindIcon(i); i++) 122 button->SetTarget(this); 123 if (fTargetCache) 124 SetTarget(fTargetCache); 125} 126 127// Draw 128void 129IconOptionsControl::Draw(BRect updateRect) 130{ 131 FillRect(updateRect, B_SOLID_LOW); 132 133 if (Label()) { 134 if (!IsEnabled()) 135 SetHighColor(tint_color(LowColor(), B_DISABLED_LABEL_TINT)); 136 else 137 SetHighColor(tint_color(LowColor(), B_DARKEN_MAX_TINT)); 138 139 font_height fh; 140 GetFontHeight(&fh); 141 BPoint p(Bounds().LeftTop()); 142 p.y += floorf(Bounds().Height() / 2.0 + (fh.ascent + fh.descent) / 2.0) - 2.0; 143 DrawString(Label(), p); 144 } 145} 146 147// FrameResized 148void 149IconOptionsControl::FrameResized(float width, float height) 150{ 151 _LayoutIcons(Bounds()); 152} 153 154// SetValue 155void 156IconOptionsControl::SetValue(int32 value) 157{ 158 if (IconButton* valueButton = _FindIcon(value)) { 159 for (int32 i = 0; IconButton* button = _FindIcon(i); i++) { 160 button->SetPressed(button == valueButton); 161 } 162 } 163} 164 165// Value 166int32 167IconOptionsControl::Value() const 168{ 169 for (int32 i = 0; IconButton* button = _FindIcon(i); i++) { 170 if (button->IsPressed()) 171 return i; 172 } 173 return -1; 174} 175 176// SetEnabled 177void 178IconOptionsControl::SetEnabled(bool enable) 179{ 180 for (int32 i = 0; IconButton* button = _FindIcon(i); i++) { 181 button->SetEnabled(enable); 182 } 183 BControl::SetEnabled(enable); 184 Invalidate(); 185} 186 187// MessageReceived 188void 189IconOptionsControl::MessageReceived(BMessage* message) 190{ 191 // catch a message from the attached IconButtons to 192 // handle switching the pressed icon 193 BView* source; 194 if (message->FindPointer("be:source", (void**)&source) >= B_OK) { 195 if (IconButton* sourceIcon = dynamic_cast<IconButton*>(source)) { 196 for (int32 i = 0; IconButton* button = _FindIcon(i); i++) { 197 if (button == sourceIcon) { 198 SetValue(i); 199 break; 200 } 201 } 202 // forward the message 203 Invoke(message); 204 return; 205 } 206 } 207 BControl::MessageReceived(message); 208} 209 210// Invoke 211status_t 212IconOptionsControl::Invoke(BMessage* message) 213{ 214 return BInvoker::Invoke(message); 215} 216 217// AddOption 218void 219IconOptionsControl::AddOption(IconButton* icon) 220{ 221 if (icon) { 222 if (!_FindIcon(0)) { 223 // first icon added, mark it 224 icon->SetPressed(true); 225 } 226 AddChild(icon); 227 icon->SetTarget(this); 228 layoutprefs(); 229 _TriggerRelayout(); 230 } 231} 232 233// _FindIcon 234IconButton* 235IconOptionsControl::_FindIcon(int32 index) const 236{ 237 if (BView* view = ChildAt(index)) 238 return dynamic_cast<IconButton*>(view); 239 return NULL; 240} 241 242// _TriggerRelayout 243void 244IconOptionsControl::_TriggerRelayout() 245{ 246 if (!Parent()) 247 return; 248 249 MView* mParent = dynamic_cast<MView*>(Parent()); 250 if (mParent) { 251 if (BWindow* window = Window()) { 252 window->PostMessage(M_RECALCULATE_SIZE); 253 } 254 } else { 255 _LayoutIcons(Bounds()); 256 } 257} 258 259// _LayoutIcons 260void 261IconOptionsControl::_LayoutIcons(BRect frame) 262{ 263 BPoint lt = frame.LeftTop(); 264 265 // sanity checks 266 if (rolemodel) 267 labelwidth = rolemodel->LabelWidth(); 268 if (labelwidth < LabelWidth()) 269 labelwidth = LabelWidth(); 270 271 lt.x += labelwidth; 272 273 for (int32 i = 0; IconButton* button = _FindIcon(i); i++) { 274 if (i == 0) { 275 lt.y = ceilf((frame.top + frame.bottom - button->mpm.mini.y) / 2.0); 276 } 277 button->MoveTo(lt); 278 button->ResizeTo(button->mpm.mini.x, button->mpm.mini.y); 279 lt = button->Frame().RightTop() + BPoint(1.0, 0.0); 280 } 281} 282