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 20 IconOptionsControl::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 37 IconOptionsControl::~IconOptionsControl() 38 { 39 } 40 41 // layoutprefs 42 minimax 43 IconOptionsControl::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 70 BRect 71 IconOptionsControl::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 83 float 84 IconOptionsControl::LabelWidth() 85 { 86 float width = ceilf(StringWidth(Label())); 87 if (width > 0.0) 88 width += LABEL_DIST; 89 return width; 90 } 91 92 // SetLabel 93 void 94 IconOptionsControl::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 108 void 109 IconOptionsControl::AttachedToWindow() 110 { 111 BControl::AttachedToWindow(); 112 113 SetViewColor(B_TRANSPARENT_32_BIT); 114 SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 115 } 116 117 // AllAttached 118 void 119 IconOptionsControl::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 128 void 129 IconOptionsControl::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 148 void 149 IconOptionsControl::FrameResized(float width, float height) 150 { 151 _LayoutIcons(Bounds()); 152 } 153 154 // SetValue 155 void 156 IconOptionsControl::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 166 int32 167 IconOptionsControl::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 177 void 178 IconOptionsControl::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 188 void 189 IconOptionsControl::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 211 status_t 212 IconOptionsControl::Invoke(BMessage* message) 213 { 214 return BInvoker::Invoke(message); 215 } 216 217 // AddOption 218 void 219 IconOptionsControl::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 234 IconButton* 235 IconOptionsControl::_FindIcon(int32 index) const 236 { 237 if (BView* view = ChildAt(index)) 238 return dynamic_cast<IconButton*>(view); 239 return NULL; 240 } 241 242 // _TriggerRelayout 243 void 244 IconOptionsControl::_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 260 void 261 IconOptionsControl::_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