btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / apps / deskbar / StatusView.cpp
blob5a9d2fc093a603c8fd6b030e5d72f43670b6b75b
1 /*
2 Open Tracker License
4 Terms and Conditions
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered
30 trademarks of Be Incorporated in the United States and other countries. Other
31 brand product names are registered trademarks or trademarks of their respective
32 holders.
33 All rights reserved.
37 #include "StatusView.h"
39 #include <errno.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <time.h>
43 #include <unistd.h>
44 #include <algorithm>
46 #include <fs_index.h>
47 #include <fs_info.h>
49 #include <Application.h>
50 #include <Beep.h>
51 #include <Bitmap.h>
52 #include <Catalog.h>
53 #include <ControlLook.h>
54 #include <Debug.h>
55 #include <Directory.h>
56 #include <FindDirectory.h>
57 #include <Locale.h>
58 #include <MenuItem.h>
59 #include <NodeInfo.h>
60 #include <NodeMonitor.h>
61 #include <Path.h>
62 #include <PopUpMenu.h>
63 #include <Roster.h>
64 #include <Screen.h>
65 #include <Volume.h>
66 #include <VolumeRoster.h>
67 #include <Window.h>
69 #include "icons.h"
71 #include "BarApp.h"
72 #include "DeskbarUtils.h"
73 #include "ResourceSet.h"
74 #include "StatusViewShelf.h"
75 #include "TimeView.h"
78 #ifdef DB_ADDONS
79 // Add-on support
81 // Item - internal item list (node, eref, etc)
82 // Icon - physical replicant handed to the DeskbarClass class
83 // AddOn - attribute based add-on
85 const char* const kInstantiateItemCFunctionName = "instantiate_deskbar_item";
86 const char* const kInstantiateEntryCFunctionName = "instantiate_deskbar_entry";
87 const char* const kReplicantSettingsFile = "replicants";
88 const char* const kReplicantPathField = "replicant_path";
90 float gMinimumWindowWidth = kGutter + kMinimumTrayWidth + kDragRegionWidth;
91 float gMaximumWindowWidth = gMinimumWindowWidth * 2;
94 static void
95 DumpItem(DeskbarItemInfo* item)
97 printf("is addon: %i, id: %" B_PRId32 "\n", item->isAddOn, item->id);
98 printf("entry_ref: %" B_PRIdDEV ", %" B_PRIdINO ", %s\n",
99 item->entryRef.device, item->entryRef.directory, item->entryRef.name);
100 printf("node_ref: %" B_PRIdDEV ", %" B_PRIdINO "\n", item->nodeRef.device,
101 item->nodeRef.node);
105 static void
106 DumpList(BList* itemlist)
108 int32 count = itemlist->CountItems() - 1;
109 if (count < 0) {
110 printf("no items in list\n");
111 return;
113 for (int32 i = count; i >= 0; i--) {
114 DeskbarItemInfo* item = (DeskbarItemInfo*)itemlist->ItemAt(i);
115 if (!item)
116 continue;
118 DumpItem(item);
121 #endif /* DB_ADDONS */
124 #undef B_TRANSLATION_CONTEXT
125 #define B_TRANSLATION_CONTEXT "Tray"
127 // don't change the name of this view to anything other than "Status"!
129 TReplicantTray::TReplicantTray(TBarView* parent, bool vertical)
131 BView(BRect(0, 0, 1, 1), "Status", B_FOLLOW_LEFT | B_FOLLOW_TOP,
132 B_WILL_DRAW | B_FRAME_EVENTS),
133 fTime(NULL),
134 fBarView(parent),
135 fShelf(new TReplicantShelf(this)),
136 fMultiRowMode(vertical),
137 fAlignmentSupport(false)
139 if (vertical)
140 fMinimumTrayWidth = gMinimumWindowWidth - kGutter - kDragRegionWidth;
141 else
142 fMinimumTrayWidth = kMinimumTrayWidth;
144 // Create the time view
145 fTime = new TTimeView(fMinimumTrayWidth, kMaxReplicantHeight - 1.0);
149 TReplicantTray::~TReplicantTray()
151 delete fShelf;
152 delete fTime;
156 void
157 TReplicantTray::AttachedToWindow()
159 BView::AttachedToWindow();
161 if (be_control_look != NULL) {
162 AdoptParentColors();
163 } else {
164 SetViewUIColor(B_MENU_BACKGROUND_COLOR, B_DARKEN_1_TINT);
166 SetDrawingMode(B_OP_COPY);
168 Window()->SetPulseRate(1000000);
170 clock_settings* clock = ((TBarApp*)be_app)->ClockSettings();
171 fTime->SetShowSeconds(clock->showSeconds);
172 fTime->SetShowDayOfWeek(clock->showDayOfWeek);
173 fTime->SetShowTimeZone(clock->showTimeZone);
175 AddChild(fTime);
177 fTime->MoveTo(Bounds().right - fTime->Bounds().Width() - kTrayPadding, 2);
179 if (!((TBarApp*)be_app)->Settings()->showClock)
180 fTime->Hide();
182 #ifdef DB_ADDONS
183 // load addons and rehydrate archives
184 #if !defined(HAIKU_TARGET_PLATFORM_LIBBE_TEST)
185 InitAddOnSupport();
186 #endif
187 #endif
188 ResizeToPreferred();
192 void
193 TReplicantTray::DetachedFromWindow()
195 #ifdef DB_ADDONS
196 // clean up add-on support
197 #if !defined(HAIKU_TARGET_PLATFORM_LIBBE_TEST)
198 DeleteAddOnSupport();
199 #endif
200 #endif
201 BView::DetachedFromWindow();
205 /*! Width is set to a minimum of kMinimumReplicantCount by kMaxReplicantWidth
206 if not in multirowmode and greater than kMinimumReplicantCount
207 the width should be calculated based on the actual replicant widths
209 void
210 TReplicantTray::GetPreferredSize(float* preferredWidth, float* preferredHeight)
212 float width = 0;
213 float height = kMinimumTrayHeight;
215 if (fMultiRowMode) {
216 width = static_cast<TBarApp*>(be_app)->Settings()->width
217 - kDragWidth - kGutter;
218 if (fRightBottomReplicant.IsValid())
219 height = fRightBottomReplicant.bottom;
220 else if (ReplicantCount() > 0) {
221 // The height will be uniform for the number of rows necessary
222 // to show all the replicants and gutters.
223 int32 rowCount = (int32)(height / kMaxReplicantHeight);
224 height = kGutter + (rowCount * kMaxReplicantHeight)
225 + ((rowCount - 1) * kIconGap) + kGutter;
226 height = std::max(kMinimumTrayHeight, height);
227 } else
228 height = kMinimumTrayHeight;
229 } else {
230 // if last replicant overruns clock then resize to accomodate
231 if (ReplicantCount() > 0) {
232 if (!fTime->IsHidden() && Bounds().right - kTrayPadding - 2
233 - fTime->Frame().Width() - kClockMargin
234 < fRightBottomReplicant.right + kClockMargin) {
235 width = fRightBottomReplicant.right + kClockMargin
236 + fTime->Frame().Width() + kTrayPadding + 2;
237 } else
238 width = fRightBottomReplicant.right + kIconGap + kGutter;
241 // this view has a fixed minimum width
242 width = std::max(fMinimumTrayWidth, width);
243 height = kGutter + static_cast<TBarApp*>(be_app)->IconSize() + kGutter;
246 *preferredWidth = width;
247 // add 1 for the border
248 *preferredHeight = height + 1;
252 void
253 TReplicantTray::AdjustPlacement()
255 // called when an add-on has been added or removed
256 // need to resize the parent of this accordingly
258 BRect bounds = Bounds();
259 float width, height;
260 GetPreferredSize(&width, &height);
262 if (width == bounds.Width() && height == bounds.Height()) {
263 // no need to change anything
264 return;
267 Parent()->ResizeToPreferred();
268 fBarView->UpdatePlacement();
269 Parent()->Invalidate();
270 Invalidate();
274 void
275 TReplicantTray::MessageReceived(BMessage* message)
277 switch (message->what) {
278 case B_LOCALE_CHANGED:
279 if (fTime == NULL)
280 return;
282 fTime->UpdateTimeFormat();
283 fTime->Update();
284 // time string reformat -> realign
285 goto realignReplicants;
287 case kShowHideTime:
288 // from context menu in clock and in this view
289 ShowHideTime();
290 break;
292 case kShowSeconds:
293 if (fTime == NULL)
294 return;
296 fTime->SetShowSeconds(!fTime->ShowSeconds());
298 // time string reformat -> realign
299 goto realignReplicants;
301 case kShowDayOfWeek:
302 if (fTime == NULL)
303 return;
305 fTime->SetShowDayOfWeek(!fTime->ShowDayOfWeek());
307 // time string reformat -> realign
308 goto realignReplicants;
310 case kShowTimeZone:
311 if (fTime == NULL)
312 return;
314 fTime->SetShowTimeZone(!fTime->ShowTimeZone());
316 // time string reformat -> realign
317 goto realignReplicants;
319 case kGetClockSettings:
321 if (fTime == NULL)
322 return;
324 bool showClock = !fTime->IsHidden();
325 bool showSeconds = fTime->ShowSeconds();
326 bool showDayOfWeek = fTime->ShowDayOfWeek();
327 bool showTimeZone = fTime->ShowTimeZone();
329 BMessage reply(kGetClockSettings);
330 reply.AddBool("showClock", showClock);
331 reply.AddBool("showSeconds", showSeconds);
332 reply.AddBool("showDayOfWeek", showDayOfWeek);
333 reply.AddBool("showTimeZone", showTimeZone);
334 message->SendReply(&reply);
335 break;
338 #ifdef DB_ADDONS
339 case B_NODE_MONITOR:
340 HandleEntryUpdate(message);
341 break;
342 #endif
344 case kRealignReplicants:
345 realignReplicants:
346 RealignReplicants();
347 AdjustPlacement();
348 break;
350 default:
351 BView::MessageReceived(message);
352 break;
357 void
358 TReplicantTray::MouseDown(BPoint where)
360 #ifdef DB_ADDONS
361 if (modifiers() & B_CONTROL_KEY)
362 DumpList(fItemList);
363 #endif
365 uint32 buttons;
367 Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
368 if (buttons == B_SECONDARY_MOUSE_BUTTON) {
369 ShowReplicantMenu(where);
370 } else {
371 BPoint save = where;
372 bigtime_t doubleClickSpeed;
373 bigtime_t start = system_time();
374 uint32 buttons;
376 get_click_speed(&doubleClickSpeed);
378 do {
379 if (fabs(where.x - save.x) > 4 || fabs(where.y - save.y) > 4)
380 // user moved out of bounds of click area
381 break;
383 if ((system_time() - start) > (2 * doubleClickSpeed)) {
384 ShowReplicantMenu(where);
385 break;
388 snooze(50000);
389 GetMouse(&where, &buttons);
390 } while (buttons);
392 BView::MouseDown(where);
396 void
397 TReplicantTray::ShowReplicantMenu(BPoint point)
399 BPopUpMenu* menu = new BPopUpMenu("", false, false);
400 menu->SetFont(be_plain_font);
402 // If clock is visible show the extended menu, otherwise show "Show clock"
404 if (!fTime->IsHidden())
405 fTime->ShowTimeOptions(ConvertToScreen(point));
406 else {
407 BMenuItem* item = new BMenuItem(B_TRANSLATE("Show clock"),
408 new BMessage(kShowHideTime));
409 menu->AddItem(item);
410 menu->SetTargetForItems(this);
411 BPoint where = ConvertToScreen(point);
412 menu->Go(where, true, true, BRect(where - BPoint(4, 4),
413 where + BPoint(4, 4)), true);
418 void
419 TReplicantTray::SetMultiRow(bool state)
421 fMultiRowMode = state;
425 void
426 TReplicantTray::ShowHideTime()
428 if (fTime == NULL)
429 return;
431 // Check from the point of view of fTime because we need to ignore
432 // whether or not the parent window is hidden.
433 if (fTime->IsHidden(fTime))
434 fTime->Show();
435 else
436 fTime->Hide();
438 RealignReplicants();
439 AdjustPlacement();
441 // Check from the point of view of fTime ignoring parent's state.
442 bool showClock = !fTime->IsHidden(fTime);
444 // Update showClock setting that gets saved to disk on quit
445 static_cast<TBarApp*>(be_app)->Settings()->showClock = showClock;
447 // Send a message to Time preferences telling it to update
448 BMessenger messenger("application/x-vnd.Haiku-Time");
449 BMessage message(kShowHideTime);
450 message.AddBool("showClock", showClock);
451 messenger.SendMessage(&message);
455 #ifdef DB_ADDONS
458 void
459 TReplicantTray::InitAddOnSupport()
461 // list to maintain refs to each rep added/deleted
462 fItemList = new BList();
463 BPath path;
465 if (GetDeskbarSettingsDirectory(path, true) == B_OK) {
466 path.Append(kReplicantSettingsFile);
468 BFile file(path.Path(), B_READ_ONLY);
469 if (file.InitCheck() == B_OK) {
470 status_t result;
471 BEntry entry;
472 int32 id;
473 BString path;
474 if (fAddOnSettings.Unflatten(&file) == B_OK) {
475 for (int32 i = 0; fAddOnSettings.FindString(kReplicantPathField,
476 i, &path) == B_OK; i++) {
477 if (entry.SetTo(path.String()) == B_OK && entry.Exists()) {
478 result = LoadAddOn(&entry, &id, false);
479 } else
480 result = B_ENTRY_NOT_FOUND;
482 if (result != B_OK) {
483 fAddOnSettings.RemoveData(kReplicantPathField, i);
484 --i;
493 void
494 TReplicantTray::DeleteAddOnSupport()
496 _SaveSettings();
498 for (int32 i = fItemList->CountItems() - 1; i >= 0; i--) {
499 DeskbarItemInfo* item = (DeskbarItemInfo*)fItemList->RemoveItem(i);
500 if (item) {
501 if (item->isAddOn)
502 watch_node(&(item->nodeRef), B_STOP_WATCHING, this, Window());
504 delete item;
507 delete fItemList;
509 // stop the volume mount/unmount watch
510 stop_watching(this, Window());
514 DeskbarItemInfo*
515 TReplicantTray::DeskbarItemFor(node_ref& nodeRef)
517 for (int32 i = fItemList->CountItems() - 1; i >= 0; i--) {
518 DeskbarItemInfo* item = (DeskbarItemInfo*)fItemList->ItemAt(i);
519 if (item == NULL)
520 continue;
522 if (item->nodeRef == nodeRef)
523 return item;
526 return NULL;
530 DeskbarItemInfo*
531 TReplicantTray::DeskbarItemFor(int32 id)
533 for (int32 i = fItemList->CountItems() - 1; i >= 0; i--) {
534 DeskbarItemInfo* item = (DeskbarItemInfo*)fItemList->ItemAt(i);
535 if (item == NULL)
536 continue;
538 if (item->id == id)
539 return item;
542 return NULL;
546 bool
547 TReplicantTray::NodeExists(node_ref& nodeRef)
549 return DeskbarItemFor(nodeRef) != NULL;
553 /*! This handles B_NODE_MONITOR & B_QUERY_UPDATE messages received
554 for the registered add-ons.
556 void
557 TReplicantTray::HandleEntryUpdate(BMessage* message)
559 int32 opcode;
560 if (message->FindInt32("opcode", &opcode) != B_OK)
561 return;
563 BPath path;
564 switch (opcode) {
565 case B_ENTRY_MOVED:
567 entry_ref ref;
568 ino_t todirectory;
569 ino_t node;
570 const char* name;
571 if (message->FindString("name", &name) == B_OK
572 && message->FindInt64("from directory", &(ref.directory))
573 == B_OK
574 && message->FindInt64("to directory", &todirectory) == B_OK
575 && message->FindInt32("device", &(ref.device)) == B_OK
576 && message->FindInt64("node", &node) == B_OK ) {
578 if (name == NULL)
579 break;
581 ref.set_name(name);
582 // change the directory reference to
583 // the new directory
584 MoveItem(&ref, todirectory);
586 break;
589 case B_ENTRY_REMOVED:
591 // entry was rm'd from the device
592 node_ref nodeRef;
593 if (message->FindInt32("device", &(nodeRef.device)) == B_OK
594 && message->FindInt64("node", &(nodeRef.node)) == B_OK) {
595 DeskbarItemInfo* item = DeskbarItemFor(nodeRef);
596 if (item == NULL)
597 break;
599 // If there is a team running where the add-on comes from,
600 // we don't want to remove the icon yet.
601 if (be_roster->IsRunning(&item->entryRef))
602 break;
604 UnloadAddOn(&nodeRef, NULL, true, false);
606 break;
612 /*! The add-ons must support the exported C function API
613 if they do, they will be loaded and added to deskbar
614 primary function is the Instantiate function
616 status_t
617 TReplicantTray::LoadAddOn(BEntry* entry, int32* id, bool addToSettings)
619 if (entry == NULL)
620 return B_BAD_VALUE;
622 node_ref nodeRef;
623 entry->GetNodeRef(&nodeRef);
624 // no duplicates
625 if (NodeExists(nodeRef))
626 return B_ERROR;
628 BNode node(entry);
629 BPath path;
630 status_t status = entry->GetPath(&path);
631 if (status != B_OK)
632 return status;
634 // load the add-on
635 image_id image = load_add_on(path.Path());
636 if (image < B_OK)
637 return image;
639 // get the view loading function symbol
640 // we first look for a symbol that takes an image_id
641 // and entry_ref pointer, if not found, go with normal
642 // instantiate function
643 BView* (*entryFunction)(image_id, const entry_ref*);
644 BView* (*itemFunction)(void);
645 BView* view = NULL;
647 entry_ref ref;
648 entry->GetRef(&ref);
650 if (get_image_symbol(image, kInstantiateEntryCFunctionName,
651 B_SYMBOL_TYPE_TEXT, (void**)&entryFunction) >= B_OK) {
652 view = (*entryFunction)(image, &ref);
653 } else if (get_image_symbol(image, kInstantiateItemCFunctionName,
654 B_SYMBOL_TYPE_TEXT, (void**)&itemFunction) >= B_OK) {
655 view = (*itemFunction)();
656 } else {
657 unload_add_on(image);
658 return B_ERROR;
661 if (view == NULL || IconExists(view->Name())) {
662 delete view;
663 unload_add_on(image);
664 return B_ERROR;
667 BMessage* data = new BMessage;
668 view->Archive(data);
669 delete view;
671 // add the rep; adds info to list
672 if (AddIcon(data, id, &ref) != B_OK)
673 delete data;
675 if (addToSettings) {
676 fAddOnSettings.AddString(kReplicantPathField, path.Path());
677 _SaveSettings();
680 return B_OK;
684 status_t
685 TReplicantTray::AddItem(int32 id, node_ref nodeRef, BEntry& entry, bool isAddOn)
687 DeskbarItemInfo* item = new DeskbarItemInfo;
688 if (item == NULL)
689 return B_NO_MEMORY;
691 item->id = id;
692 item->isAddOn = isAddOn;
694 if (entry.GetRef(&item->entryRef) != B_OK) {
695 item->entryRef.device = -1;
696 item->entryRef.directory = -1;
697 item->entryRef.name = NULL;
699 item->nodeRef = nodeRef;
701 fItemList->AddItem(item);
703 if (isAddOn)
704 watch_node(&nodeRef, B_WATCH_NAME | B_WATCH_ATTR, this, Window());
706 return B_OK;
710 /** from entry_removed message, when attribute removed
711 * or when a device is unmounted (use removeall, by device)
714 void
715 TReplicantTray::UnloadAddOn(node_ref* nodeRef, dev_t* device, bool which,
716 bool removeAll)
718 for (int32 i = fItemList->CountItems() - 1; i >= 0; i--) {
719 DeskbarItemInfo* item = (DeskbarItemInfo*)fItemList->ItemAt(i);
720 if (item == NULL)
721 continue;
723 if ((which && nodeRef != NULL && item->nodeRef == *nodeRef)
724 || (device != NULL && item->nodeRef.device == *device)) {
726 if (device != NULL && be_roster->IsRunning(&item->entryRef))
727 continue;
729 RemoveIcon(item->id);
731 if (!removeAll)
732 break;
738 void
739 TReplicantTray::RemoveItem(int32 id)
741 DeskbarItemInfo* item = DeskbarItemFor(id);
742 if (item == NULL)
743 return;
745 // attribute was added via Deskbar API (AddItem(entry_ref*, int32*)
746 if (item->isAddOn) {
747 BPath path(&item->entryRef);
748 BString storedPath;
749 for (int32 i = 0;
750 fAddOnSettings.FindString(kReplicantPathField, i, &storedPath)
751 == B_OK; i++) {
752 if (storedPath == path.Path()) {
753 fAddOnSettings.RemoveData(kReplicantPathField, i);
754 break;
757 _SaveSettings();
759 BNode node(&item->entryRef);
760 watch_node(&item->nodeRef, B_STOP_WATCHING, this, Window());
763 fItemList->RemoveItem(item);
764 delete item;
768 /** ENTRY_MOVED message, moving only occurs on a device
769 * copying will occur (ENTRY_CREATED) between devices
772 void
773 TReplicantTray::MoveItem(entry_ref* ref, ino_t toDirectory)
775 if (ref == NULL)
776 return;
778 // scan for a matching entry_ref and update it
780 // don't need to change node info as it does not change
782 for (int32 i = fItemList->CountItems() - 1; i >= 0; i--) {
783 DeskbarItemInfo* item = (DeskbarItemInfo*)fItemList->ItemAt(i);
784 if (item == NULL)
785 continue;
787 if (strcmp(item->entryRef.name, ref->name) == 0
788 && item->entryRef.device == ref->device
789 && item->entryRef.directory == ref->directory) {
790 item->entryRef.directory = toDirectory;
791 break;
796 #endif // add-on support
798 // external add-on API routines
799 // called using the new BDeskbar class
801 // existence of icon/replicant by name or ID
802 // returns opposite
803 // note: name and id are semi-private limiting
804 // the ability of non-host apps to remove
805 // icons without a little bit of work
807 /** for a specific id
808 * return the name of the replicant (name of view)
811 status_t
812 TReplicantTray::ItemInfo(int32 id, const char** name)
814 if (id < 0)
815 return B_BAD_VALUE;
817 int32 index;
818 int32 temp;
819 BView* view = ViewAt(&index, &temp, id, false);
820 if (view != NULL) {
821 *name = view->Name();
822 return B_OK;
825 return B_ERROR;
829 /** for a specific name
830 * return the id (internal to Deskbar)
833 status_t
834 TReplicantTray::ItemInfo(const char* name, int32* id)
836 if (name == NULL || *name == '\0')
837 return B_BAD_VALUE;
839 int32 index;
840 BView* view = ViewAt(&index, id, name);
842 return view != NULL ? B_OK : B_ERROR;
846 /** at a specific index
847 * return both the name and the id of the replicant
850 status_t
851 TReplicantTray::ItemInfo(int32 index, const char** name, int32* id)
853 if (index < 0)
854 return B_BAD_VALUE;
856 BView* view;
857 fShelf->ReplicantAt(index, &view, (uint32*)id, NULL);
858 if (view != NULL) {
859 *name = view->Name();
860 return B_OK;
863 return B_ERROR;
867 /** replicant exists, by id/index */
869 bool
870 TReplicantTray::IconExists(int32 target, bool byIndex)
872 int32 index;
873 int32 id;
874 BView* view = ViewAt(&index, &id, target, byIndex);
876 return view && index >= 0;
880 /** replicant exists, by name */
882 bool
883 TReplicantTray::IconExists(const char* name)
885 if (name == NULL || *name == '\0')
886 return false;
888 int32 index;
889 int32 id;
890 BView* view = ViewAt(&index, &id, name);
892 return view != NULL && index >= 0;
896 int32
897 TReplicantTray::ReplicantCount() const
899 return fShelf->CountReplicants();
903 /*! Message must contain an archivable view for later rehydration.
904 This function takes over ownership of the provided message on success
905 only.
906 Returns the current replicant ID.
908 status_t
909 TReplicantTray::AddIcon(BMessage* archive, int32* id, const entry_ref* addOn)
911 if (archive == NULL || id == NULL)
912 return B_BAD_VALUE;
914 // find entry_ref
916 entry_ref ref;
917 if (addOn != NULL) {
918 // Use it if we got it
919 ref = *addOn;
920 } else {
921 const char* signature;
923 status_t status = archive->FindString("add_on", &signature);
924 if (status == B_OK) {
925 BRoster roster;
926 status = roster.FindApp(signature, &ref);
928 if (status != B_OK)
929 return status;
932 BFile file;
933 status_t status = file.SetTo(&ref, B_READ_ONLY);
934 if (status != B_OK)
935 return status;
937 node_ref nodeRef;
938 status = file.GetNodeRef(&nodeRef);
939 if (status != B_OK)
940 return status;
942 BEntry entry(&ref, true);
943 // TODO: this resolves an eventual link for the item being added - this
944 // is okay for now, but in multi-user environments, one might want to
945 // have links that carry the be:deskbar_item_status attribute
946 status = entry.InitCheck();
947 if (status != B_OK)
948 return status;
950 *id = 999;
951 if (archive->what == B_ARCHIVED_OBJECT)
952 archive->what = 0;
954 BRect originalBounds = archive->FindRect("_frame");
955 // this is a work-around for buggy replicants that change their size in
956 // AttachedToWindow() (such as "SVM")
958 // TODO: check for name collisions?
959 status = fShelf->AddReplicant(archive, BPoint(1, 1));
960 if (status != B_OK)
961 return status;
963 int32 count = ReplicantCount();
964 BView* view;
965 fShelf->ReplicantAt(count - 1, &view, (uint32*)id, NULL);
967 if (view != NULL && originalBounds != view->Bounds()) {
968 // The replicant changed its size when added to the window, so we need
969 // to recompute all over again (it's already done once via
970 // BShelf::AddReplicant() and TReplicantShelf::CanAcceptReplicantView())
971 RealignReplicants();
974 float oldWidth = Bounds().Width();
975 float oldHeight = Bounds().Height();
976 float width, height;
977 GetPreferredSize(&width, &height);
978 if (oldWidth != width || oldHeight != height)
979 AdjustPlacement();
981 // add the item to the add-on list
983 AddItem(*id, nodeRef, entry, addOn != NULL);
984 return B_OK;
988 void
989 TReplicantTray::RemoveIcon(int32 target, bool byIndex)
991 if (target < 0)
992 return;
994 int32 index;
995 int32 id;
996 BView* view = ViewAt(&index, &id, target, byIndex);
997 if (view != NULL && index >= 0) {
998 // remove the reference from the item list & the shelf
999 RemoveItem(id);
1000 fShelf->DeleteReplicant(index);
1002 // force a placement update, !! need to fix BShelf
1003 RealReplicantAdjustment(index);
1008 void
1009 TReplicantTray::RemoveIcon(const char* name)
1011 if (name == NULL || *name == '\0')
1012 return;
1014 int32 index;
1015 int32 id;
1016 BView* view = ViewAt(&index, &id, name);
1017 if (view != NULL && index >= 0) {
1018 // remove the reference from the item list & shelf
1019 RemoveItem(id);
1020 fShelf->DeleteReplicant(index);
1022 // force a placement update, !! need to fix BShelf
1023 RealReplicantAdjustment(index);
1028 void
1029 TReplicantTray::RealReplicantAdjustment(int32 startIndex)
1031 if (startIndex < 0)
1032 return;
1034 if (startIndex == fLastReplicant)
1035 startIndex = 0;
1037 // reset the locations of all replicants after the one deleted
1038 RealignReplicants(startIndex);
1040 float oldWidth = Bounds().Width();
1041 float oldHeight = Bounds().Height();
1042 float width, height;
1043 GetPreferredSize(&width, &height);
1044 if (oldWidth != width || oldHeight != height) {
1045 // resize view to accomodate the replicants, redraw as necessary
1046 AdjustPlacement();
1051 /** looking for a replicant by id/index
1052 * return the view and index
1055 BView*
1056 TReplicantTray::ViewAt(int32* index, int32* id, int32 target, bool byIndex)
1058 *index = -1;
1060 BView* view;
1061 if (byIndex) {
1062 if (fShelf->ReplicantAt(target, &view, (uint32*)id)) {
1063 if (view != NULL) {
1064 *index = target;
1066 return view;
1069 } else {
1070 int32 count = ReplicantCount() - 1;
1071 int32 localid;
1072 for (int32 repIndex = count; repIndex >= 0; repIndex--) {
1073 fShelf->ReplicantAt(repIndex, &view, (uint32*)&localid);
1074 if (localid == target && view != NULL) {
1075 *index = repIndex;
1076 *id = localid;
1078 return view;
1083 return NULL;
1087 /** looking for a replicant with a view by name
1088 * return the view, index and the id of the replicant
1091 BView*
1092 TReplicantTray::ViewAt(int32* index, int32* id, const char* name)
1094 *index = -1;
1095 *id = -1;
1097 BView* view;
1098 int32 count = ReplicantCount() - 1;
1099 for (int32 repIndex = count; repIndex >= 0; repIndex--) {
1100 fShelf->ReplicantAt(repIndex, &view, (uint32*)id);
1101 if (view != NULL && view->Name() != NULL
1102 && strcmp(name, view->Name()) == 0) {
1103 *index = repIndex;
1105 return view;
1109 return NULL;
1113 /** Shelf will call to determine where and if
1114 * the replicant is to be added
1117 bool
1118 TReplicantTray::AcceptAddon(BRect replicantFrame, BMessage* message)
1120 if (message == NULL)
1121 return false;
1123 if (replicantFrame.Height() > kMaxReplicantHeight)
1124 return false;
1126 alignment align = B_ALIGN_LEFT;
1127 if (fAlignmentSupport && message->HasBool("deskbar:dynamic_align")) {
1128 if (!fBarView->Vertical())
1129 align = B_ALIGN_RIGHT;
1130 else
1131 align = fBarView->Left() ? B_ALIGN_LEFT : B_ALIGN_RIGHT;
1132 } else if (message->HasInt32("deskbar:align"))
1133 message->FindInt32("deskbar:align", (int32*)&align);
1135 if (message->HasInt32("deskbar:private_align"))
1136 message->FindInt32("deskbar:private_align", (int32*)&align);
1137 else
1138 align = B_ALIGN_LEFT;
1140 BPoint loc = LocationForReplicant(ReplicantCount(),
1141 replicantFrame.Width());
1142 message->AddPoint("_pjp_loc", loc);
1144 return true;
1148 /** based on the previous (index - 1) replicant in the list
1149 * calculate where the left point should be for this
1150 * replicant. replicant will flow to the right on its own
1153 BPoint
1154 TReplicantTray::LocationForReplicant(int32 index, float replicantWidth)
1156 BPoint loc(kTrayPadding, 2);
1157 if (fBarView->Vertical()) {
1158 if (!fBarView->Left())
1159 loc.x += kDragWidth; // move past dragger
1160 } else
1161 loc.x += 1; // keeps everything lined up nicely
1163 if (fMultiRowMode) {
1164 // try to find free space in every row
1165 for (int32 row = 0; ; loc.y += kMaxReplicantHeight + kIconGap, row++) {
1166 // determine free space in this row
1167 BRect rowRect(loc.x, loc.y,
1168 loc.x + static_cast<TBarApp*>(be_app)->Settings()->width
1169 - (kTrayPadding + kDragWidth + kGutter) * 2,
1170 loc.y + kMaxReplicantHeight);
1171 if (row == 0 && !fTime->IsHidden())
1172 rowRect.right -= kClockMargin + fTime->Frame().Width();
1174 BRect replicantRect = rowRect;
1175 for (int32 i = 0; i < index; i++) {
1176 BView* view = NULL;
1177 fShelf->ReplicantAt(i, &view);
1178 if (view == NULL || view->Frame().top != rowRect.top)
1179 continue;
1181 // push this replicant placement past the last one
1182 replicantRect.left = view->Frame().right + kIconGap + 1;
1185 // calculated left position, add replicantWidth to get right position
1186 replicantRect.right = replicantRect.left + replicantWidth;
1188 // check if replicant fits in this row
1189 if (replicantRect.right < rowRect.right) {
1190 // replicant fits in this row
1191 loc = replicantRect.LeftTop();
1192 break;
1195 // check next row
1197 } else if (index > 0) {
1198 // get the last replicant added for placement reference
1199 BView* view = NULL;
1200 fShelf->ReplicantAt(index - 1, &view);
1201 if (view != NULL) {
1202 // push this replicant placement past the last one
1203 loc.x = view->Frame().right + kIconGap + 1;
1204 loc.y = view->Frame().top;
1208 if (loc.y > fRightBottomReplicant.top
1209 || (loc.y == fRightBottomReplicant.top
1210 && loc.x > fRightBottomReplicant.left)) {
1211 fRightBottomReplicant.Set(loc.x, loc.y, loc.x + replicantWidth,
1212 loc.y + kMaxReplicantHeight);
1213 fLastReplicant = index;
1216 return loc;
1220 BRect
1221 TReplicantTray::IconFrame(int32 target, bool byIndex)
1223 int32 index;
1224 int32 id;
1225 BView* view = ViewAt(&index, &id, target, byIndex);
1227 return view != NULL ? view->Frame() : BRect(0, 0, 0, 0);
1231 BRect
1232 TReplicantTray::IconFrame(const char* name)
1234 if (name == NULL)
1235 return BRect(0, 0, 0, 0);
1237 int32 index;
1238 int32 id;
1239 BView* view = ViewAt(&index, &id, name);
1241 return view != NULL ? view->Frame() : BRect(0, 0, 0, 0);
1245 /** Scan from the startIndex and reset the location
1246 * as defined in LocationForReplicant()
1249 void
1250 TReplicantTray::RealignReplicants(int32 startIndex)
1252 if (startIndex < 0)
1253 startIndex = 0;
1255 int32 replicantCount = ReplicantCount();
1256 if (replicantCount <= 0)
1257 return;
1259 if (startIndex == 0)
1260 fRightBottomReplicant.Set(0, 0, 0, 0);
1262 BView* view = NULL;
1263 for (int32 index = startIndex; index < replicantCount; index++) {
1264 fShelf->ReplicantAt(index, &view);
1265 if (view == NULL)
1266 continue;
1268 float replicantWidth = view->Frame().Width();
1269 BPoint loc = LocationForReplicant(index, replicantWidth);
1270 if (view->Frame().LeftTop() != loc)
1271 view->MoveTo(loc);
1276 status_t
1277 TReplicantTray::_SaveSettings()
1279 status_t result;
1280 BPath path;
1281 if ((result = GetDeskbarSettingsDirectory(path, true)) == B_OK) {
1282 path.Append(kReplicantSettingsFile);
1284 BFile file(path.Path(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
1285 if ((result = file.InitCheck()) == B_OK)
1286 result = fAddOnSettings.Flatten(&file);
1289 return result;
1293 void
1294 TReplicantTray::SaveTimeSettings()
1296 if (fTime == NULL)
1297 return;
1299 clock_settings* settings = ((TBarApp*)be_app)->ClockSettings();
1300 settings->showSeconds = fTime->ShowSeconds();
1301 settings->showDayOfWeek = fTime->ShowDayOfWeek();
1302 settings->showTimeZone = fTime->ShowTimeZone();
1306 // #pragma mark - TDragRegion
1309 /*! Draggable region that is asynchronous so that dragging does not block
1310 other activities.
1312 TDragRegion::TDragRegion(TBarView* parent, BView* replicantTray)
1314 BControl(BRect(0, 0, 0, 0), "", "", NULL, B_FOLLOW_NONE,
1315 B_WILL_DRAW | B_FRAME_EVENTS),
1316 fBarView(parent),
1317 fReplicantTray(replicantTray),
1318 fDragLocation(kAutoPlaceDragRegion)
1323 void
1324 TDragRegion::AttachedToWindow()
1326 BView::AttachedToWindow();
1328 if (be_control_look != NULL)
1329 SetViewUIColor(B_MENU_BACKGROUND_COLOR, 1.1);
1330 else
1331 SetViewUIColor(B_MENU_BACKGROUND_COLOR);
1333 ResizeToPreferred();
1337 void
1338 TDragRegion::GetPreferredSize(float* width, float* height)
1340 fReplicantTray->ResizeToPreferred();
1341 *width = fReplicantTray->Bounds().Width();
1342 *height = fReplicantTray->Bounds().Height();
1344 if (fDragLocation != kNoDragRegion)
1345 *width += kDragWidth + kGutter;
1346 else
1347 *width += 6;
1349 *height += 2;
1353 void
1354 TDragRegion::Draw(BRect updateRect)
1356 rgb_color menuColor = ViewColor();
1357 rgb_color hilite = tint_color(menuColor, B_DARKEN_1_TINT);
1358 rgb_color ldark = tint_color(menuColor, 1.02);
1359 rgb_color dark = tint_color(menuColor, B_DARKEN_2_TINT);
1360 rgb_color vvdark = tint_color(menuColor, B_DARKEN_4_TINT);
1361 rgb_color light = tint_color(menuColor, B_LIGHTEN_2_TINT);
1363 BRect frame(Bounds());
1364 BeginLineArray(4);
1366 if (be_control_look != NULL) {
1367 if (fBarView->Vertical()) {
1368 AddLine(frame.LeftTop(), frame.RightTop(), dark);
1369 AddLine(BPoint(frame.left, frame.top + 1),
1370 BPoint(frame.right, frame.top + 1), ldark);
1371 AddLine(frame.LeftBottom(), frame.RightBottom(), hilite);
1372 } else if (fBarView->AcrossTop() || fBarView->AcrossBottom()) {
1373 AddLine(frame.LeftTop(),
1374 BPoint(frame.left, frame.bottom), dark);
1375 AddLine(BPoint(frame.left + 1, frame.top + 1),
1376 BPoint(frame.right - 1, frame.top + 1), light);
1377 AddLine(BPoint(frame.right, frame.top + 2),
1378 BPoint(frame.right, frame.bottom), hilite);
1379 AddLine(BPoint(frame.left + 1, frame.bottom),
1380 BPoint(frame.right - 1, frame.bottom), hilite);
1382 } else {
1383 if (fBarView->Vertical()) {
1384 AddLine(frame.LeftTop(), frame.RightTop(), light);
1385 AddLine(frame.LeftTop(), frame.LeftBottom(), light);
1386 AddLine(frame.RightBottom(), frame.RightTop(), hilite);
1387 } else if (fBarView->AcrossTop()) {
1388 AddLine(BPoint(frame.left, frame.top + 1),
1389 BPoint(frame.right - 1, frame.top + 1), light);
1390 AddLine(frame.RightTop(), frame.RightBottom(), vvdark);
1391 AddLine(BPoint(frame.right - 1, frame.top + 2),
1392 BPoint(frame.right - 1, frame.bottom - 1), hilite);
1393 AddLine(frame.LeftBottom(),
1394 BPoint(frame.right - 1, frame.bottom), hilite);
1395 } else if (fBarView->AcrossBottom()) {
1396 AddLine(BPoint(frame.left, frame.top + 1),
1397 BPoint(frame.right - 1, frame.top + 1), light);
1398 AddLine(frame.LeftBottom(), frame.RightBottom(), hilite);
1399 AddLine(frame.RightTop(), frame.RightBottom(), vvdark);
1400 AddLine(BPoint(frame.right - 1, frame.top + 1),
1401 BPoint(frame.right - 1, frame.bottom - 1), hilite);
1405 EndLineArray();
1407 if (fDragLocation != kDontDrawDragRegion || fDragLocation != kNoDragRegion)
1408 DrawDragRegion();
1412 void
1413 TDragRegion::DrawDragRegion()
1415 BRect dragRegion(DragRegion());
1417 rgb_color menuColor = ViewColor();
1418 rgb_color menuHilite = menuColor;
1419 if (IsTracking()) {
1420 // draw drag region highlighted if tracking mouse
1421 menuHilite = tint_color(menuColor, B_HIGHLIGHT_BACKGROUND_TINT);
1422 SetHighColor(menuHilite);
1423 FillRect(dragRegion);
1424 } else {
1425 SetHighColor(menuColor);
1426 FillRect(dragRegion);
1429 rgb_color vdark = tint_color(menuHilite, B_DARKEN_3_TINT);
1430 rgb_color light = tint_color(menuHilite, B_LIGHTEN_2_TINT);
1432 BeginLineArray(dragRegion.IntegerHeight());
1433 BPoint where;
1434 where.x = floorf((dragRegion.left + dragRegion.right) / 2 + 0.5) - 1;
1435 where.y = dragRegion.top + 2;
1437 while (where.y + 1 <= dragRegion.bottom) {
1438 AddLine(where, where, vdark);
1439 AddLine(where + BPoint(1, 1), where + BPoint(1, 1), light);
1441 where.y += 3;
1443 EndLineArray();
1447 BRect
1448 TDragRegion::DragRegion() const
1450 float kTopBottomInset = 2;
1451 float kLeftRightInset = 1;
1452 if (be_control_look != NULL) {
1453 kTopBottomInset = 1;
1454 kLeftRightInset = 0;
1457 BRect dragRegion(Bounds());
1458 dragRegion.top += kTopBottomInset;
1459 dragRegion.bottom -= kTopBottomInset;
1461 bool placeOnLeft = false;
1462 if (fDragLocation == kAutoPlaceDragRegion) {
1463 if (fBarView->Vertical() && fBarView->Left())
1464 placeOnLeft = true;
1465 else
1466 placeOnLeft = false;
1467 } else
1468 placeOnLeft = fDragLocation == kDragRegionLeft;
1470 if (placeOnLeft) {
1471 dragRegion.left += kLeftRightInset;
1472 dragRegion.right = dragRegion.left + kDragWidth;
1473 } else {
1474 dragRegion.right += kLeftRightInset;
1475 dragRegion.left = dragRegion.right - kDragWidth;
1478 return dragRegion;
1482 void
1483 TDragRegion::MouseDown(BPoint where)
1485 uint32 buttons;
1486 BPoint mouseLoc;
1488 BRect dragRegion(DragRegion());
1489 dragRegion.InsetBy(-2, -2);
1490 // DragRegion() is designed for drawing, not clicking
1492 if (!dragRegion.Contains(where))
1493 return;
1495 while (true) {
1496 GetMouse(&mouseLoc, &buttons);
1497 if (buttons == 0)
1498 break;
1500 if ((Window()->Flags() & B_ASYNCHRONOUS_CONTROLS) != 0) {
1501 fPreviousPosition = where;
1502 SetTracking(true);
1503 SetMouseEventMask(B_POINTER_EVENTS,
1504 B_NO_POINTER_HISTORY | B_LOCK_WINDOW_FOCUS);
1505 Invalidate(DragRegion());
1506 break;
1509 snooze(25000);
1514 void
1515 TDragRegion::MouseUp(BPoint where)
1517 if (IsTracking()) {
1518 SetTracking(false);
1519 Invalidate(DragRegion());
1520 } else
1521 BControl::MouseUp(where);
1525 bool
1526 TDragRegion::SwitchModeForRect(BPoint where, BRect rect,
1527 bool newVertical, bool newLeft, bool newTop, int32 newState)
1529 if (!rect.Contains(where)) {
1530 // not our rect
1531 return false;
1534 if (newVertical == fBarView->Vertical() && newLeft == fBarView->Left()
1535 && newTop == fBarView->Top() && newState == fBarView->State()) {
1536 // already in the correct mode
1537 return true;
1540 fBarView->ChangeState(newState, newVertical, newLeft, newTop, true);
1542 return true;
1546 void
1547 TDragRegion::MouseMoved(BPoint where, uint32 code, const BMessage* message)
1549 if (IsTracking()) {
1550 BScreen screen;
1551 BRect frame = screen.Frame();
1553 float hDivider = frame.Width() / 6;
1554 hDivider = (hDivider < gMinimumWindowWidth + 10)
1555 ? gMinimumWindowWidth + 10 : hDivider;
1556 float miniDivider = frame.top + kMiniHeight + 10;
1557 float vDivider = frame.Height() / 2;
1558 #ifdef FULL_MODE
1559 float thirdScreen = frame.Height() / 3;
1560 #endif
1561 BRect topLeft(frame.left, frame.top, frame.left + hDivider,
1562 miniDivider);
1563 BRect topMiddle(frame.left + hDivider, frame.top, frame.right
1564 - hDivider, vDivider);
1565 BRect topRight(frame.right - hDivider, frame.top, frame.right,
1566 miniDivider);
1568 #ifdef FULL_MODE
1569 vDivider = miniDivider + thirdScreen;
1570 #endif
1571 BRect middleLeft(frame.left, miniDivider, frame.left + hDivider,
1572 vDivider);
1573 BRect middleRight(frame.right - hDivider, miniDivider, frame.right,
1574 vDivider);
1576 #ifdef FULL_MODE
1577 BRect leftSide(frame.left, vDivider, frame.left + hDivider,
1578 frame.bottom - thirdScreen);
1579 BRect rightSide(frame.right - hDivider, vDivider, frame.right,
1580 frame.bottom - thirdScreen);
1582 vDivider = frame.bottom - thirdScreen;
1583 #endif
1584 BRect bottomLeft(frame.left, vDivider, frame.left + hDivider,
1585 frame.bottom);
1586 BRect bottomMiddle(frame.left + hDivider, vDivider, frame.right
1587 - hDivider, frame.bottom);
1588 BRect bottomRight(frame.right - hDivider, vDivider, frame.right,
1589 frame.bottom);
1591 if (where != fPreviousPosition) {
1592 fPreviousPosition = where;
1593 ConvertToScreen(&where);
1595 // use short circuit evaluation for convenience
1596 if (SwitchModeForRect(where, topLeft, true, true, true, kMiniState)
1597 || SwitchModeForRect(where, topMiddle, false, true, true,
1598 kExpandoState)
1599 || SwitchModeForRect(where, topRight, true, false, true,
1600 kMiniState)
1601 || SwitchModeForRect(where, middleLeft, true, true, true,
1602 kExpandoState)
1603 || SwitchModeForRect(where, middleRight, true, false, true,
1604 kExpandoState)
1606 #ifdef FULL_MODE
1607 || SwitchModeForRect(where, leftSide, true, true, true,
1608 kFullState)
1609 || SwitchModeForRect(where, rightSide, true, false, true,
1610 kFullState)
1611 #endif
1612 || SwitchModeForRect(where, bottomLeft, true, true, false,
1613 kMiniState)
1614 || SwitchModeForRect(where, bottomMiddle, false, true, false,
1615 kExpandoState)
1616 || SwitchModeForRect(where, bottomRight, true, false, false,
1617 kMiniState))
1620 } else
1621 BControl::MouseMoved(where, code, message);
1625 int32
1626 TDragRegion::DragRegionLocation() const
1628 return fDragLocation;
1632 void
1633 TDragRegion::SetDragRegionLocation(int32 location)
1635 if (location == fDragLocation)
1636 return;
1638 fDragLocation = location;
1639 Invalidate();
1643 // #pragma mark - TResizeControl
1646 /*! Draggable region that is asynchronous so that resizing does not block.
1648 TResizeControl::TResizeControl(TBarView* barView)
1650 BControl(BRect(0, kDragWidth, 0, kMenuBarHeight), "", "", NULL,
1651 B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS),
1652 fBarView(barView)
1657 TResizeControl::~TResizeControl()
1662 void
1663 TResizeControl::AttachedToWindow()
1665 BView::AttachedToWindow();
1667 if (be_control_look != NULL)
1668 SetViewUIColor(B_MENU_BACKGROUND_COLOR, 1.1);
1669 else
1670 SetViewUIColor(B_MENU_BACKGROUND_COLOR);
1674 void
1675 TResizeControl::Draw(BRect updateRect)
1677 if (!fBarView->Vertical())
1678 return;
1680 BRect dragRegion(Bounds());
1682 int32 height = dragRegion.IntegerHeight();
1683 if (height <= 0)
1684 return;
1686 rgb_color menuColor = ViewColor();
1687 rgb_color menuHilite = menuColor;
1688 if (IsTracking()) {
1689 // draw drag region highlighted if tracking mouse
1690 menuHilite = tint_color(menuColor, B_HIGHLIGHT_BACKGROUND_TINT);
1691 SetHighColor(menuHilite);
1692 FillRect(dragRegion);
1693 } else {
1694 SetHighColor(menuColor);
1695 FillRect(dragRegion);
1698 rgb_color vdark = tint_color(menuHilite, B_DARKEN_3_TINT);
1699 rgb_color light = tint_color(menuHilite, B_LIGHTEN_2_TINT);
1701 BeginLineArray(height);
1702 BPoint where;
1703 where.x = floorf((dragRegion.left + dragRegion.right) / 2 + 0.5) - 1;
1704 where.y = dragRegion.top + 2;
1706 while (where.y + 1 <= dragRegion.bottom) {
1707 AddLine(where, where, vdark);
1708 AddLine(where + BPoint(1, 1), where + BPoint(1, 1), light);
1710 where.y += 3;
1712 EndLineArray();
1716 void
1717 TResizeControl::MouseDown(BPoint where)
1719 uint32 buttons;
1720 BPoint mouseLoc;
1722 while (true) {
1723 GetMouse(&mouseLoc, &buttons);
1724 if (buttons == 0)
1725 break;
1727 if ((Window()->Flags() & B_ASYNCHRONOUS_CONTROLS) != 0) {
1728 SetTracking(true);
1729 SetMouseEventMask(B_POINTER_EVENTS,
1730 B_NO_POINTER_HISTORY | B_LOCK_WINDOW_FOCUS);
1731 Invalidate();
1732 break;
1735 snooze(25000);
1740 void
1741 TResizeControl::MouseUp(BPoint where)
1743 if (IsTracking()) {
1744 SetTracking(false);
1745 Invalidate();
1746 } else
1747 BControl::MouseUp(where);
1751 void
1752 TResizeControl::MouseMoved(BPoint where, uint32 code,
1753 const BMessage* dragMessage)
1755 if (fBarView->Vertical()) {
1756 if (IsResizing()) {
1757 float windowWidth = Window()->Frame().Width();
1758 float delta = 0;
1759 BPoint whereScreen = ConvertToScreen(where);
1761 if (fBarView->Left()) {
1762 delta = whereScreen.x - Window()->Frame().right;
1763 if (delta > 0 && windowWidth >= gMaximumWindowWidth)
1764 ; // do nothing
1765 else if (delta < 0 && windowWidth <= gMinimumWindowWidth)
1766 ; // do nothing
1767 else
1768 Window()->ResizeBy(delta, 0);
1769 } else {
1770 delta = Window()->Frame().left - whereScreen.x;
1771 if (delta > 0 && windowWidth >= gMaximumWindowWidth)
1772 ; // do nothing
1773 else if (delta < 0 && windowWidth <= gMinimumWindowWidth)
1774 ; // do nothing
1775 else {
1776 Window()->MoveBy(delta, 0);
1777 Window()->ResizeBy(delta, 0);
1781 windowWidth = Window()->Frame().Width();
1785 BControl::MouseMoved(where, code, dragMessage);