1 /* 2 * Copyright 2001-2006, Haiku Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Marc Flerackers (mflerackers@androme.be) 7 * Stephan Aßmus <superstippi@gmx.de> 8 */ 9 10 #include <stdio.h> 11 12 #include <BMCPrivate.h> 13 #include <MenuField.h> 14 #include <MenuItem.h> 15 #include <Message.h> 16 #include <Region.h> 17 #include <Window.h> 18 19 /* 20 _BMCFilter_::_BMCFilter_(BMenuField *menuField, uint32) 21 { 22 } 23 24 25 _BMCFilter_::~_BMCFilter_() 26 { 27 } 28 29 30 filter_result 31 _BMCFilter_::Filter(BMessage *message, BHandler **handler) 32 { 33 } 34 35 36 _BMCFilter_ & 37 _BMCFilter_::operator=(const _BMCFilter_ &) 38 { 39 return *this; 40 }*/ 41 42 43 _BMCMenuBar_::_BMCMenuBar_(BRect frame, bool fixed_size, BMenuField *menuField) 44 : BMenuBar(frame, "_mc_mb_", B_FOLLOW_LEFT | B_FOLLOW_TOP, B_ITEMS_IN_ROW, 45 !fixed_size) 46 { 47 SetFlags(Flags() | B_FRAME_EVENTS); 48 SetBorder(B_BORDER_CONTENTS); 49 50 fMenuField = menuField; 51 fFixedSize = fixed_size; 52 fRunner = NULL; 53 54 float left, top, right, bottom; 55 56 GetItemMargins(&left, &top, &right, &bottom); 57 // give a bit more space to draw the small thumb 58 left -= 1; 59 right += 3; 60 SetItemMargins(left, top, right, bottom); 61 62 SetMaxContentWidth(frame.Width() - (left + right)); 63 } 64 65 66 _BMCMenuBar_::_BMCMenuBar_(BMessage *data) 67 : BMenuBar(data) 68 { 69 SetFlags(Flags() | B_FRAME_EVENTS); 70 71 bool rsize_to_fit; 72 73 if (data->FindBool("_rsize_to_fit", &rsize_to_fit) == B_OK) 74 fFixedSize = !rsize_to_fit; 75 else 76 fFixedSize = true; 77 } 78 79 80 _BMCMenuBar_::~_BMCMenuBar_() 81 { 82 } 83 84 85 BArchivable * 86 _BMCMenuBar_::Instantiate(BMessage *data) 87 { 88 if (validate_instantiation(data, "_BMCMenuBar_")) 89 return new _BMCMenuBar_(data); 90 91 return NULL; 92 } 93 94 95 void 96 _BMCMenuBar_::AttachedToWindow() 97 { 98 fMenuField = static_cast<BMenuField *>(Parent()); 99 100 BMenuBar *menuBar = Window()->KeyMenuBar(); 101 BMenuBar::AttachedToWindow(); 102 Window()->SetKeyMenuBar(menuBar); 103 } 104 105 106 void 107 _BMCMenuBar_::Draw(BRect updateRect) 108 { 109 // draw the right side with the popup marker 110 111 // prevent the original BMenuBar's Draw from 112 // drawing in those parts 113 BRect bounds(Bounds()); 114 bounds.right -= 10.0; 115 bounds.bottom -= 1.0; 116 117 BRegion clipping(bounds); 118 ConstrainClippingRegion(&clipping); 119 120 BMenuBar::Draw(updateRect); 121 122 // restore clipping 123 ConstrainClippingRegion(NULL); 124 bounds.right += 10.0; 125 bounds.bottom += 1.0; 126 127 // prepare some colors 128 rgb_color normalNoTint = ui_color(B_MENU_BACKGROUND_COLOR); 129 rgb_color noTint = tint_color(normalNoTint, 0.74); 130 rgb_color darken4; 131 rgb_color normalDarken4; 132 rgb_color darken1; 133 rgb_color lighten1; 134 rgb_color lighten2; 135 136 if (IsEnabled()) { 137 darken4 = tint_color(noTint, B_DARKEN_4_TINT); 138 normalDarken4 = tint_color(normalNoTint, B_DARKEN_4_TINT); 139 darken1 = tint_color(noTint, B_DARKEN_1_TINT); 140 lighten1 = tint_color(noTint, B_LIGHTEN_1_TINT); 141 lighten2 = tint_color(noTint, B_LIGHTEN_2_TINT); 142 } else { 143 darken4 = tint_color(noTint, B_DARKEN_2_TINT); 144 normalDarken4 = tint_color(normalNoTint, B_DARKEN_2_TINT); 145 darken1 = tint_color(noTint, (B_NO_TINT + B_DARKEN_1_TINT) / 2.0); 146 lighten1 = tint_color(noTint, (B_NO_TINT + B_LIGHTEN_1_TINT) / 2.0); 147 lighten2 = tint_color(noTint, B_LIGHTEN_1_TINT); 148 } 149 150 BRect r(bounds); 151 r.left = r.right - 10.0; 152 153 BeginLineArray(6); 154 // bottom below item text, darker then BMenuBar 155 // would normaly draw it 156 AddLine(BPoint(bounds.left, r.bottom), 157 BPoint(r.left - 1.0, r.bottom), normalDarken4); 158 159 // bottom below popup marker 160 AddLine(BPoint(r.left, r.bottom), 161 BPoint(r.right, r.bottom), darken4); 162 // right of popup marker 163 AddLine(BPoint(r.right, r.bottom - 1), 164 BPoint(r.right, r.top), darken4); 165 // top above popup marker 166 AddLine(BPoint(r.left, r.top), 167 BPoint(r.right - 2, r.top), lighten2); 168 169 r.top += 1; 170 r.bottom -= 1; 171 r.right -= 1; 172 173 // bottom below popup marker 174 AddLine(BPoint(r.left, r.bottom), 175 BPoint(r.right, r.bottom), darken1); 176 // right of popup marker 177 AddLine(BPoint(r.right, r.bottom - 1), 178 BPoint(r.right, r.top), darken1); 179 EndLineArray(); 180 181 r.bottom -= 1; 182 r.right -= 1; 183 SetHighColor(noTint); 184 FillRect(r); 185 186 // popup marker 187 BPoint center(roundf((r.left + r.right) / 2.0), 188 roundf((r.top + r.bottom) / 2.0)); 189 BPoint triangle[3]; 190 triangle[0] = center + BPoint(-2.5, -0.5); 191 triangle[1] = center + BPoint(2.5, -0.5); 192 triangle[2] = center + BPoint(0.0, 2.0); 193 194 uint32 flags = Flags(); 195 SetFlags(flags | B_SUBPIXEL_PRECISE); 196 197 SetHighColor(normalDarken4); 198 FillTriangle(triangle[0], triangle[1], triangle[2]); 199 200 SetFlags(flags); 201 } 202 203 204 void 205 _BMCMenuBar_::FrameResized(float width, float height) 206 { 207 // we need to take care of resizing and cleaning up 208 // the parent menu field 209 float diff = Frame().right - fMenuField->Bounds().right; 210 if (Window()) { 211 if (diff > 0) { 212 // clean up the dirty right border of 213 // the menu field when enlarging 214 BRect dirty(fMenuField->Bounds()); 215 dirty.left = dirty.right - 2; 216 fMenuField->Invalidate(dirty); 217 218 // clean up the arrow part 219 dirty = Bounds(); 220 dirty.right -= diff; 221 dirty.left = dirty.right - 12; 222 Invalidate(dirty); 223 224 } else if (diff < 0) { 225 // clean up the dirty right line of 226 // the menu field when shrinking 227 BRect dirty(fMenuField->Bounds()); 228 dirty.left = dirty.right + diff + 1; 229 dirty.right = dirty.left + 1; 230 fMenuField->Invalidate(dirty); 231 232 // clean up the arrow part 233 dirty = Bounds(); 234 dirty.left = dirty.right - 12; 235 Invalidate(dirty); 236 } 237 } 238 239 // we have been shrinked or enlarged and need to take 240 // of the size of the parent menu field as well 241 // NOTE: no worries about follow mode, we follow left and top 242 fMenuField->ResizeBy(diff + 2, 0.0); 243 BMenuBar::FrameResized(width, height); 244 } 245 246 247 void 248 _BMCMenuBar_::MessageReceived(BMessage *msg) 249 { 250 switch (msg->what) { 251 case 'TICK': 252 { 253 BMenuItem *item = ItemAt(0); 254 255 if (item && item->Submenu() && item->Submenu()->Window()) { 256 BMessage message(B_KEY_DOWN); 257 258 message.AddInt8("byte", B_ESCAPE); 259 message.AddInt8("key", B_ESCAPE); 260 message.AddInt32("modifiers", 0); 261 message.AddInt8("raw_char", B_ESCAPE); 262 263 Window()->PostMessage(&message, this, NULL); 264 } 265 } 266 // fall through 267 default: 268 BMenuBar::MessageReceived(msg); 269 break; 270 } 271 } 272 273 274 void 275 _BMCMenuBar_::MakeFocus(bool focused) 276 { 277 if (IsFocus() == focused) 278 return; 279 280 BMenuBar::MakeFocus(focused); 281 282 if (focused) { 283 BMessage message('TICK'); 284 //fRunner = new BMessageRunner(BMessenger(this, NULL, NULL), &message, 285 // 50000, -1); 286 } else if (fRunner) { 287 //delete fRunner; 288 fRunner = NULL; 289 } 290 291 if (focused) 292 return; 293 294 fMenuField->fSelected = false; 295 fMenuField->fTransition = true; 296 297 BRect bounds(fMenuField->Bounds()); 298 299 fMenuField->Invalidate(BRect(bounds.left, bounds.top, fMenuField->fDivider, 300 bounds.bottom)); 301 } 302 303 304 void 305 _BMCMenuBar_::MouseDown(BPoint where) 306 { 307 // Don't show the associated menu if it's disabled 308 if (fMenuField->IsEnabled() && SubmenuAt(0)->IsEnabled()) 309 BMenuBar::MouseDown(where); 310 } 311 312 313 _BMCMenuBar_ 314 &_BMCMenuBar_::operator=(const _BMCMenuBar_ &) 315 { 316 return *this; 317 } 318