xref: /haiku/src/apps/icon-o-matic/gui/StyleListView.cpp (revision 445d4fd926c569e7b9ae28017da86280aaecbae2)
1 /*
2  * Copyright 2006-2012, Stephan Aßmus <superstippi@gmx.de>.
3  * All rights reserved. Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "StyleListView.h"
8 
9 #include <new>
10 #include <stdio.h>
11 
12 #include <Application.h>
13 #include <Catalog.h>
14 #include <ListItem.h>
15 #include <Locale.h>
16 #include <Menu.h>
17 #include <MenuItem.h>
18 #include <Message.h>
19 #include <Mime.h>
20 #include <Window.h>
21 
22 #include "AddStylesCommand.h"
23 #include "AssignStyleCommand.h"
24 #include "CurrentColor.h"
25 #include "CommandStack.h"
26 #include "GradientTransformable.h"
27 #include "MoveStylesCommand.h"
28 #include "PathSourceShape.h"
29 #include "RemoveStylesCommand.h"
30 #include "Style.h"
31 #include "Observer.h"
32 #include "ResetTransformationCommand.h"
33 #include "Shape.h"
34 #include "ShapeContainer.h"
35 #include "Selection.h"
36 #include "Util.h"
37 
38 
39 #undef B_TRANSLATION_CONTEXT
40 #define B_TRANSLATION_CONTEXT "Icon-O-Matic-StylesList"
41 
42 
43 using std::nothrow;
44 
45 static const float kMarkWidth		= 14.0;
46 static const float kBorderOffset	= 3.0;
47 static const float kTextOffset		= 4.0;
48 
49 enum {
50 	MSG_ADD							= 'adst',
51 	MSG_REMOVE						= 'rmst',
52 	MSG_DUPLICATE					= 'dpst',
53 	MSG_RESET_TRANSFORMATION		= 'rstr',
54 };
55 
56 class StyleListItem : public SimpleItem,
57 					 public Observer {
58 public:
59 	StyleListItem(Style* s, StyleListView* listView, bool markEnabled)
60 		:
61 		SimpleItem(""),
62 		style(NULL),
63 		fListView(listView),
64 		fMarkEnabled(markEnabled),
65 		fMarked(false)
66 	{
67 		SetStyle(s);
68 	}
69 
70 	virtual ~StyleListItem()
71 	{
72 		SetStyle(NULL);
73 	}
74 
75 	// SimpleItem interface
76 	virtual	void Draw(BView* owner, BRect itemFrame, uint32 flags)
77 	{
78 		SimpleItem::DrawBackground(owner, itemFrame, flags);
79 
80 		// text
81 		if (IsSelected())
82 			owner->SetHighColor(ui_color(B_LIST_SELECTED_ITEM_TEXT_COLOR));
83 		else
84 			owner->SetHighColor(ui_color(B_LIST_ITEM_TEXT_COLOR));
85 		font_height fh;
86 		owner->GetFontHeight(&fh);
87 		BString truncatedString(Text());
88 		owner->TruncateString(&truncatedString, B_TRUNCATE_MIDDLE,
89 			itemFrame.Width() - kBorderOffset - kMarkWidth - kTextOffset
90 			- kBorderOffset);
91 		float height = itemFrame.Height();
92 		float textHeight = fh.ascent + fh.descent;
93 		BPoint pos;
94 		pos.x = itemFrame.left + kBorderOffset + kMarkWidth + kTextOffset;
95 		pos.y = itemFrame.top + ceilf((height - textHeight) / 2.0 + fh.ascent);
96 		owner->DrawString(truncatedString.String(), pos);
97 
98 		if (!fMarkEnabled)
99 			return;
100 
101 		// mark
102 		BRect markRect = itemFrame;
103 		float markRectBorderTint = B_DARKEN_1_TINT;
104 		float markRectFillTint = 1.04;
105 		float markTint = B_DARKEN_4_TINT;
106 					// Dark Themes
107 		rgb_color lowColor = owner->LowColor();
108 		if (lowColor.red + lowColor.green + lowColor.blue < 128 * 3) {
109 			markRectBorderTint = B_LIGHTEN_2_TINT;
110 			markRectFillTint = 0.85;
111 			markTint = 0.1;
112 		}
113 		markRect.left += kBorderOffset;
114 		markRect.right = markRect.left + kMarkWidth;
115 		markRect.top = (markRect.top + markRect.bottom - kMarkWidth) / 2.0;
116 		markRect.bottom = markRect.top + kMarkWidth;
117 		owner->SetHighColor(tint_color(owner->LowColor(), markRectBorderTint));
118 		owner->StrokeRect(markRect);
119 		markRect.InsetBy(1, 1);
120 		owner->SetHighColor(tint_color(owner->LowColor(), markRectFillTint));
121 		owner->FillRect(markRect);
122 		if (fMarked) {
123 			markRect.InsetBy(2, 2);
124 			owner->SetHighColor(tint_color(owner->LowColor(),
125 				markTint));
126 			owner->SetPenSize(2);
127 			owner->StrokeLine(markRect.LeftTop(), markRect.RightBottom());
128 			owner->StrokeLine(markRect.LeftBottom(), markRect.RightTop());
129 			owner->SetPenSize(1);
130 		}
131 	}
132 
133 	// Observer interface
134 	virtual	void	ObjectChanged(const Observable* object)
135 	{
136 		UpdateText();
137 	}
138 
139 	// StyleListItem
140 	void SetStyle(Style* s)
141 	{
142 		if (s == style)
143 			return;
144 
145 		if (style) {
146 			style->RemoveObserver(this);
147 			style->ReleaseReference();
148 		}
149 
150 		style = s;
151 
152 		if (style) {
153 			style->AcquireReference();
154 			style->AddObserver(this);
155 			UpdateText();
156 		}
157 	}
158 
159 	void UpdateText()
160 	{
161 		SetText(style->Name());
162 		Invalidate();
163 	}
164 
165 	void SetMarkEnabled(bool enabled)
166 	{
167 		if (fMarkEnabled == enabled)
168 			return;
169 		fMarkEnabled = enabled;
170 		Invalidate();
171 	}
172 
173 	void SetMarked(bool marked)
174 	{
175 		if (fMarked == marked)
176 			return;
177 		fMarked = marked;
178 		Invalidate();
179 	}
180 
181 	void Invalidate()
182 	{
183 		if (fListView->LockLooper()) {
184 			fListView->InvalidateItem(fListView->IndexOf(this));
185 			fListView->UnlockLooper();
186 		}
187 	}
188 
189 public:
190 	Style*			style;
191 
192 private:
193 	StyleListView*	fListView;
194 	bool			fMarkEnabled;
195 	bool			fMarked;
196 };
197 
198 
199 class ShapeStyleListener : public ShapeListener,
200 	public ShapeContainerListener {
201 public:
202 	ShapeStyleListener(StyleListView* listView)
203 		:
204 		fListView(listView),
205 		fShape(NULL)
206 	{
207 	}
208 
209 	virtual ~ShapeStyleListener()
210 	{
211 		SetShape(NULL);
212 	}
213 
214 	// ShapeListener interface
215 	virtual	void TransformerAdded(Transformer* t, int32 index)
216 	{
217 	}
218 
219 	virtual	void TransformerRemoved(Transformer* t)
220 	{
221 	}
222 
223 	virtual void StyleChanged(Style* oldStyle, Style* newStyle)
224 	{
225 		fListView->_SetStyleMarked(oldStyle, false);
226 		fListView->_SetStyleMarked(newStyle, true);
227 	}
228 
229 	// ShapeContainerListener interface
230 	virtual void ShapeAdded(Shape* shape, int32 index)
231 	{
232 	}
233 
234 	virtual void ShapeRemoved(Shape* shape)
235 	{
236 		fListView->SetCurrentShape(NULL);
237 	}
238 
239 	// ShapeStyleListener
240 	void SetShape(PathSourceShape* shape)
241 	{
242 		if (fShape == shape)
243 			return;
244 
245 		if (fShape)
246 			fShape->RemoveListener(this);
247 
248 		fShape = shape;
249 
250 		if (fShape)
251 			fShape->AddListener(this);
252 	}
253 
254 	PathSourceShape* CurrentShape() const
255 	{
256 		return fShape;
257 	}
258 
259 private:
260 	StyleListView*		fListView;
261 	PathSourceShape*	fShape;
262 };
263 
264 
265 // #pragma mark -
266 
267 
268 StyleListView::StyleListView(BRect frame, const char* name, BMessage* message,
269 	BHandler* target)
270 	:
271 	SimpleListView(frame, name, NULL, B_SINGLE_SELECTION_LIST),
272 	fMessage(message),
273 	fStyleContainer(NULL),
274 	fShapeContainer(NULL),
275 	fCommandStack(NULL),
276 	fCurrentColor(NULL),
277 
278 	fCurrentShape(NULL),
279 	fShapeListener(new ShapeStyleListener(this)),
280 
281 	fMenu(NULL)
282 {
283 	SetTarget(target);
284 }
285 
286 
287 StyleListView::~StyleListView()
288 {
289 	_MakeEmpty();
290 	delete fMessage;
291 
292 	if (fStyleContainer != NULL)
293 		fStyleContainer->RemoveListener(this);
294 
295 	if (fShapeContainer != NULL)
296 		fShapeContainer->RemoveListener(fShapeListener);
297 
298 	delete fShapeListener;
299 }
300 
301 
302 // #pragma mark -
303 
304 
305 void
306 StyleListView::MessageReceived(BMessage* message)
307 {
308 	switch (message->what) {
309 		case MSG_ADD:
310 		{
311 			Style* style;
312 			AddStylesCommand* command;
313 			rgb_color color;
314 			if (fCurrentColor != NULL)
315 				color = fCurrentColor->Color();
316 			else {
317 				color.red = 0;
318 				color.green = 0;
319 				color.blue = 0;
320 				color.alpha = 255;
321 			}
322 			new_style(color, fStyleContainer, &style, &command);
323 			fCommandStack->Perform(command);
324 			break;
325 		}
326 
327 		case MSG_REMOVE:
328 			RemoveSelected();
329 			break;
330 
331 		case MSG_DUPLICATE:
332 		{
333 			int32 count = CountSelectedItems();
334 			int32 index = 0;
335 			BList items;
336 			for (int32 i = 0; i < count; i++) {
337 				index = CurrentSelection(i);
338 				BListItem* item = ItemAt(index);
339 				if (item)
340 					items.AddItem((void*)item);
341 			}
342 			CopyItems(items, index + 1);
343 			break;
344 		}
345 
346 		case MSG_RESET_TRANSFORMATION:
347 		{
348 			int32 count = CountSelectedItems();
349 			BList gradients;
350 			for (int32 i = 0; i < count; i++) {
351 				StyleListItem* item = dynamic_cast<StyleListItem*>(
352 					ItemAt(CurrentSelection(i)));
353 				if (item && item->style && item->style->Gradient()) {
354 					if (!gradients.AddItem((void*)item->style->Gradient()))
355 						break;
356 				}
357 			}
358 			count = gradients.CountItems();
359 			if (count <= 0)
360 				break;
361 
362 			Transformable* transformables[count];
363 			for (int32 i = 0; i < count; i++) {
364 				Gradient* gradient = (Gradient*)gradients.ItemAtFast(i);
365 				transformables[i] = gradient;
366 			}
367 
368 			ResetTransformationCommand* command
369 				= new ResetTransformationCommand(transformables, count);
370 
371 			fCommandStack->Perform(command);
372 			break;
373 		}
374 
375 		default:
376 			SimpleListView::MessageReceived(message);
377 			break;
378 	}
379 }
380 
381 
382 void
383 StyleListView::SelectionChanged()
384 {
385 	SimpleListView::SelectionChanged();
386 
387 	if (!fSyncingToSelection) {
388 		// NOTE: single selection list
389 		StyleListItem* item
390 			= dynamic_cast<StyleListItem*>(ItemAt(CurrentSelection(0)));
391 		if (fMessage) {
392 			BMessage message(*fMessage);
393 			message.AddPointer("style", item ? (void*)item->style : NULL);
394 			Invoke(&message);
395 		}
396 	}
397 
398 	_UpdateMenu();
399 }
400 
401 
402 void
403 StyleListView::MouseDown(BPoint where)
404 {
405 	if (fCurrentShape == NULL) {
406 		SimpleListView::MouseDown(where);
407 		return;
408 	}
409 
410 	bool handled = false;
411 	int32 index = IndexOf(where);
412 	StyleListItem* item = dynamic_cast<StyleListItem*>(ItemAt(index));
413 	if (item != NULL) {
414 		BRect itemFrame(ItemFrame(index));
415 		itemFrame.right = itemFrame.left + kBorderOffset + kMarkWidth
416 			+ kTextOffset / 2.0;
417 		Style* style = item->style;
418 		if (itemFrame.Contains(where)) {
419 			// set the style on the shape
420 			if (fCommandStack) {
421 				::Command* command = new AssignStyleCommand(
422 											fCurrentShape, style);
423 				fCommandStack->Perform(command);
424 			} else {
425 				fCurrentShape->SetStyle(style);
426 			}
427 			handled = true;
428 		}
429 	}
430 
431 	if (!handled)
432 		SimpleListView::MouseDown(where);
433 }
434 
435 
436 void
437 StyleListView::MakeDragMessage(BMessage* message) const
438 {
439 	SimpleListView::MakeDragMessage(message);
440 	message->AddPointer("container", fStyleContainer);
441 	int32 count = CountSelectedItems();
442 	for (int32 i = 0; i < count; i++) {
443 		StyleListItem* item = dynamic_cast<StyleListItem*>(
444 			ItemAt(CurrentSelection(i)));
445 		if (item != NULL) {
446 			message->AddPointer("style", (void*)item->style);
447 			BMessage archive;
448 			if (item->style->Archive(&archive, true) == B_OK)
449 				message->AddMessage("style archive", &archive);
450 		} else
451 			break;
452 	}
453 }
454 
455 
456 bool
457 StyleListView::AcceptDragMessage(const BMessage* message) const
458 {
459 	return SimpleListView::AcceptDragMessage(message);
460 }
461 
462 
463 void
464 StyleListView::SetDropTargetRect(const BMessage* message, BPoint where)
465 {
466 	SimpleListView::SetDropTargetRect(message, where);
467 }
468 
469 
470 bool
471 StyleListView::HandleDropMessage(const BMessage* message, int32 dropIndex)
472 {
473 	// Let SimpleListView handle drag-sorting (when drag came from ourself)
474 	if (SimpleListView::HandleDropMessage(message, dropIndex))
475 		return true;
476 
477 	if (fCommandStack == NULL || fStyleContainer == NULL)
478 		return false;
479 
480 	// Drag may have come from another instance, like in another window.
481 	// Reconstruct the Styles from the archive and add them at the drop
482 	// index.
483 	int index = 0;
484 	BList styles;
485 	while (true) {
486 		BMessage archive;
487 		if (message->FindMessage("style archive", index, &archive) != B_OK)
488 			break;
489 		Style* style = new(std::nothrow) Style(&archive);
490 		if (style == NULL)
491 			break;
492 
493 		if (!styles.AddItem(style)) {
494 			delete style;
495 			break;
496 		}
497 
498 		index++;
499 	}
500 
501 	int32 count = styles.CountItems();
502 	if (count == 0)
503 		return false;
504 
505 	AddStylesCommand* command = new(std::nothrow) AddStylesCommand(
506 		fStyleContainer, (Style**)styles.Items(), count, dropIndex);
507 
508 	if (command == NULL) {
509 		for (int32 i = 0; i < count; i++)
510 			delete (Style*)styles.ItemAtFast(i);
511 		return false;
512 	}
513 
514 	fCommandStack->Perform(command);
515 
516 	return true;
517 }
518 
519 
520 void
521 StyleListView::MoveItems(BList& items, int32 toIndex)
522 {
523 	if (fCommandStack == NULL || fStyleContainer == NULL)
524 		return;
525 
526 	int32 count = items.CountItems();
527 	Style** styles = new (nothrow) Style*[count];
528 	if (styles == NULL)
529 		return;
530 
531 	for (int32 i = 0; i < count; i++) {
532 		StyleListItem* item
533 			= dynamic_cast<StyleListItem*>((BListItem*)items.ItemAtFast(i));
534 		styles[i] = item ? item->style : NULL;
535 	}
536 
537 	MoveStylesCommand* command = new (nothrow) MoveStylesCommand(
538 		fStyleContainer, styles, count, toIndex);
539 	if (command == NULL) {
540 		delete[] styles;
541 		return;
542 	}
543 
544 	fCommandStack->Perform(command);
545 }
546 
547 
548 void
549 StyleListView::CopyItems(BList& items, int32 toIndex)
550 {
551 	if (fCommandStack == NULL || fStyleContainer == NULL)
552 		return;
553 
554 	int32 count = items.CountItems();
555 	Style* styles[count];
556 
557 	for (int32 i = 0; i < count; i++) {
558 		StyleListItem* item
559 			= dynamic_cast<StyleListItem*>((BListItem*)items.ItemAtFast(i));
560 		styles[i] = item ? new (nothrow) Style(*item->style) : NULL;
561 	}
562 
563 	AddStylesCommand* command
564 		= new (nothrow) AddStylesCommand(fStyleContainer,
565 										 styles, count, toIndex);
566 	if (!command) {
567 		for (int32 i = 0; i < count; i++)
568 			delete styles[i];
569 		return;
570 	}
571 
572 	fCommandStack->Perform(command);
573 }
574 
575 
576 void
577 StyleListView::RemoveItemList(BList& items)
578 {
579 	if (!fCommandStack || !fStyleContainer)
580 		return;
581 
582 	int32 count = items.CountItems();
583 	Style* styles[count];
584 	for (int32 i = 0; i < count; i++) {
585 		StyleListItem* item = dynamic_cast<StyleListItem*>(
586 			(BListItem*)items.ItemAtFast(i));
587 		if (item)
588 			styles[i] = item->style;
589 		else
590 			styles[i] = NULL;
591 	}
592 
593 	RemoveStylesCommand* command
594 		= new (nothrow) RemoveStylesCommand(fStyleContainer,
595 											styles, count);
596 	fCommandStack->Perform(command);
597 }
598 
599 
600 BListItem*
601 StyleListView::CloneItem(int32 index) const
602 {
603 	if (StyleListItem* item = dynamic_cast<StyleListItem*>(ItemAt(index))) {
604 		return new StyleListItem(item->style,
605 			const_cast<StyleListView*>(this),
606 			fCurrentShape != NULL);
607 	}
608 	return NULL;
609 }
610 
611 
612 int32
613 StyleListView::IndexOfSelectable(Selectable* selectable) const
614 {
615 	Style* style = dynamic_cast<Style*>(selectable);
616 	if (style == NULL)
617 		return -1;
618 
619 	int count = CountItems();
620 	for (int32 i = 0; i < count; i++) {
621 		if (SelectableFor(ItemAt(i)) == style)
622 			return i;
623 	}
624 
625 	return -1;
626 }
627 
628 
629 Selectable*
630 StyleListView::SelectableFor(BListItem* item) const
631 {
632 	StyleListItem* styleItem = dynamic_cast<StyleListItem*>(item);
633 	if (styleItem != NULL)
634 		return styleItem->style;
635 	return NULL;
636 }
637 
638 
639 // #pragma mark -
640 
641 
642 void
643 StyleListView::StyleAdded(Style* style, int32 index)
644 {
645 	// NOTE: we are in the thread that messed with the
646 	// StyleContainer, so no need to lock the
647 	// container, when this is changed to asynchronous
648 	// notifications, then it would need to be read-locked!
649 	if (!LockLooper())
650 		return;
651 
652 	if (_AddStyle(style, index))
653 		Select(index);
654 
655 	UnlockLooper();
656 }
657 
658 
659 void
660 StyleListView::StyleRemoved(Style* style)
661 {
662 	// NOTE: we are in the thread that messed with the
663 	// StyleContainer, so no need to lock the
664 	// container, when this is changed to asynchronous
665 	// notifications, then it would need to be read-locked!
666 	if (!LockLooper())
667 		return;
668 
669 	// NOTE: we're only interested in Style objects
670 	_RemoveStyle(style);
671 
672 	UnlockLooper();
673 }
674 
675 
676 // #pragma mark -
677 
678 
679 void
680 StyleListView::SetMenu(BMenu* menu)
681 {
682 	if (fMenu == menu)
683 		return;
684 
685 	fMenu = menu;
686 	if (fMenu == NULL)
687 		return;
688 
689 	fAddMI = new BMenuItem(B_TRANSLATE("Add"), new BMessage(MSG_ADD));
690 	fMenu->AddItem(fAddMI);
691 
692 	fMenu->AddSeparatorItem();
693 
694 	fDuplicateMI = new BMenuItem(B_TRANSLATE("Duplicate"),
695 		new BMessage(MSG_DUPLICATE));
696 	fMenu->AddItem(fDuplicateMI);
697 
698 	fResetTransformationMI = new BMenuItem(B_TRANSLATE("Reset transformation"),
699 		new BMessage(MSG_RESET_TRANSFORMATION));
700 	fMenu->AddItem(fResetTransformationMI);
701 
702 	fMenu->AddSeparatorItem();
703 
704 	fRemoveMI = new BMenuItem(B_TRANSLATE("Remove"), new BMessage(MSG_REMOVE));
705 	fMenu->AddItem(fRemoveMI);
706 
707 	fMenu->SetTargetForItems(this);
708 
709 	_UpdateMenu();
710 }
711 
712 
713 void
714 StyleListView::SetStyleContainer(StyleContainer* container)
715 {
716 	if (fStyleContainer == container)
717 		return;
718 
719 	// detach from old container
720 	if (fStyleContainer != NULL)
721 		fStyleContainer->RemoveListener(this);
722 
723 	_MakeEmpty();
724 
725 	fStyleContainer = container;
726 
727 	if (fStyleContainer == NULL)
728 		return;
729 
730 	fStyleContainer->AddListener(this);
731 
732 	// sync
733 	int32 count = fStyleContainer->CountStyles();
734 	for (int32 i = 0; i < count; i++)
735 		_AddStyle(fStyleContainer->StyleAtFast(i), i);
736 }
737 
738 
739 void
740 StyleListView::SetShapeContainer(ShapeContainer* container)
741 {
742 	if (fShapeContainer == container)
743 		return;
744 
745 	// detach from old container
746 	if (fShapeContainer)
747 		fShapeContainer->RemoveListener(fShapeListener);
748 
749 	fShapeContainer = container;
750 
751 	if (fShapeContainer)
752 		fShapeContainer->AddListener(fShapeListener);
753 }
754 
755 
756 void
757 StyleListView::SetCommandStack(CommandStack* stack)
758 {
759 	fCommandStack = stack;
760 }
761 
762 
763 void
764 StyleListView::SetCurrentColor(CurrentColor* color)
765 {
766 	fCurrentColor = color;
767 }
768 
769 
770 void
771 StyleListView::SetCurrentShape(Shape* shape)
772 {
773 	PathSourceShape* pathSourceShape = dynamic_cast<PathSourceShape*>(shape);
774 
775 	if (fCurrentShape == pathSourceShape)
776 		return;
777 
778 	fCurrentShape = pathSourceShape;
779 	fShapeListener->SetShape(pathSourceShape);
780 
781 	_UpdateMarks();
782 }
783 
784 
785 // #pragma mark -
786 
787 
788 bool
789 StyleListView::_AddStyle(Style* style, int32 index)
790 {
791 	if (style != NULL) {
792 		 return AddItem(new StyleListItem(
793 		 	style, this, fCurrentShape != NULL), index);
794 	}
795 	return false;
796 }
797 
798 
799 bool
800 StyleListView::_RemoveStyle(Style* style)
801 {
802 	StyleListItem* item = _ItemForStyle(style);
803 	if (item != NULL && RemoveItem(item)) {
804 		delete item;
805 		return true;
806 	}
807 	return false;
808 }
809 
810 
811 StyleListItem*
812 StyleListView::_ItemForStyle(Style* style) const
813 {
814 	int count = CountItems();
815 	for (int32 i = 0; i < count; i++) {
816 		StyleListItem* item = dynamic_cast<StyleListItem*>(ItemAt(i));
817 		if (item == NULL)
818 			continue;
819 		if (item->style == style)
820 			return item;
821 	}
822 	return NULL;
823 }
824 
825 
826 // #pragma mark -
827 
828 
829 void
830 StyleListView::_UpdateMarks()
831 {
832 	int32 count = CountItems();
833 	if (fCurrentShape) {
834 		// enable display of marks and mark items whoes
835 		// style is contained in fCurrentShape
836 		for (int32 i = 0; i < count; i++) {
837 			StyleListItem* item = dynamic_cast<StyleListItem*>(ItemAt(i));
838 			if (item == NULL)
839 				continue;
840 			item->SetMarkEnabled(true);
841 			item->SetMarked(fCurrentShape->Style() == item->style);
842 		}
843 	} else {
844 		// disable display of marks
845 		for (int32 i = 0; i < count; i++) {
846 			StyleListItem* item = dynamic_cast<StyleListItem*>(ItemAt(i));
847 			if (item == NULL)
848 				continue;
849 			item->SetMarkEnabled(false);
850 		}
851 	}
852 
853 	Invalidate();
854 }
855 
856 
857 void
858 StyleListView::_SetStyleMarked(Style* style, bool marked)
859 {
860 	StyleListItem* item = _ItemForStyle(style);
861 	if (item != NULL)
862 		item->SetMarked(marked);
863 }
864 
865 
866 void
867 StyleListView::_UpdateMenu()
868 {
869 	if (fMenu == NULL)
870 		return;
871 
872 	bool gotSelection = CurrentSelection(0) >= 0;
873 
874 	fDuplicateMI->SetEnabled(gotSelection);
875 	// TODO: only enable fResetTransformationMI if styles
876 	// with gradients are selected!
877 	fResetTransformationMI->SetEnabled(gotSelection);
878 	fRemoveMI->SetEnabled(gotSelection);
879 }
880 
881