* Copyright 2006-2011, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/
#include "StyleView.h"
#include <new>
#include <Catalog.h>
#include <GridLayout.h>
#include <GroupLayout.h>
#include <Locale.h>
#include <Menu.h>
#include <MenuBar.h>
#include <MenuField.h>
#include <MenuItem.h>
#include <Message.h>
#include <PopUpMenu.h>
#include <SpaceLayoutItem.h>
#include <Window.h>
#include "CommandStack.h"
#include "CurrentColor.h"
#include "GradientTransformable.h"
#include "GradientControl.h"
#include "SetColorCommand.h"
#include "SetGradientCommand.h"
#include "Style.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Icon-O-Matic-StyleTypes"
using std::nothrow;
enum {
MSG_SET_COLOR = 'stcl',
MSG_SET_STYLE_TYPE = 'stst',
MSG_SET_GRADIENT_TYPE = 'stgt',
};
enum {
STYLE_TYPE_COLOR = 0,
STYLE_TYPE_GRADIENT,
};
StyleView::StyleView(BRect frame)
:
BView("style view", 0),
fCommandStack(NULL),
fCurrentColor(NULL),
fStyle(NULL),
fGradient(NULL),
fIgnoreCurrentColorNotifications(false),
fIgnoreControlGradientNotifications(false),
fPreviousBounds(frame.OffsetToCopy(B_ORIGIN))
{
SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
BMenu* menu = new BPopUpMenu(B_TRANSLATE("<unavailable>"));
BMessage* message = new BMessage(MSG_SET_STYLE_TYPE);
message->AddInt32("type", STYLE_TYPE_COLOR);
menu->AddItem(new BMenuItem(B_TRANSLATE("Color"), message));
message = new BMessage(MSG_SET_STYLE_TYPE);
message->AddInt32("type", STYLE_TYPE_GRADIENT);
menu->AddItem(new BMenuItem(B_TRANSLATE("Gradient"), message));
BGridLayout* layout = new BGridLayout(5, 5);
SetLayout(layout);
fStyleType = new BMenuField(B_TRANSLATE("Style type"), menu);
menu = new BPopUpMenu(B_TRANSLATE("<unavailable>"));
message = new BMessage(MSG_SET_GRADIENT_TYPE);
message->AddInt32("type", GRADIENT_LINEAR);
menu->AddItem(new BMenuItem(B_TRANSLATE("Linear"), message));
message = new BMessage(MSG_SET_GRADIENT_TYPE);
message->AddInt32("type", GRADIENT_CIRCULAR);
menu->AddItem(new BMenuItem(B_TRANSLATE("Radial"), message));
message = new BMessage(MSG_SET_GRADIENT_TYPE);
message->AddInt32("type", GRADIENT_DIAMOND);
menu->AddItem(new BMenuItem(B_TRANSLATE("Diamond"), message));
message = new BMessage(MSG_SET_GRADIENT_TYPE);
message->AddInt32("type", GRADIENT_CONIC);
menu->AddItem(new BMenuItem(B_TRANSLATE("Conic"), message));
fGradientType = new BMenuField(B_TRANSLATE("Gradient type"), menu);
fGradientControl = new GradientControl(new BMessage(MSG_SET_COLOR), this);
layout->AddItem(BSpaceLayoutItem::CreateVerticalStrut(3), 0, 0, 4);
layout->AddItem(BSpaceLayoutItem::CreateHorizontalStrut(3), 0, 1, 1, 3);
layout->AddItem(fStyleType->CreateLabelLayoutItem(), 1, 1);
layout->AddItem(fStyleType->CreateMenuBarLayoutItem(), 2, 1);
layout->AddItem(fGradientType->CreateLabelLayoutItem(), 1, 2);
layout->AddItem(fGradientType->CreateMenuBarLayoutItem(), 2, 2);
layout->AddView(fGradientControl, 1, 3, 2);
layout->AddItem(BSpaceLayoutItem::CreateHorizontalStrut(3), 3, 1, 1, 3);
layout->AddItem(BSpaceLayoutItem::CreateVerticalStrut(3), 0, 4, 4);
fStyleType->SetEnabled(false);
fGradientType->SetEnabled(false);
fGradientControl->SetEnabled(false);
fGradientControl->Gradient()->AddObserver(this);
}
StyleView::~StyleView()
{
SetStyle(NULL);
SetCurrentColor(NULL);
fGradientControl->Gradient()->RemoveObserver(this);
if (fGradient.IsSet()) {
fGradient->RemoveObserver(this);
}
}
void
StyleView::AttachedToWindow()
{
fStyleType->Menu()->SetTargetForItems(this);
fGradientType->Menu()->SetTargetForItems(this);
}
void
StyleView::FrameResized(float width, float height)
{
fPreviousBounds = Bounds();
}
void
StyleView::MessageReceived(BMessage* message)
{
switch (message->what) {
case MSG_SET_STYLE_TYPE:
{
int32 type;
if (message->FindInt32("type", &type) == B_OK)
_SetStyleType(type);
break;
}
case MSG_SET_GRADIENT_TYPE:
{
int32 type;
if (message->FindInt32("type", &type) == B_OK)
_SetGradientType(type);
break;
}
case MSG_SET_COLOR:
case MSG_GRADIENT_CONTROL_FOCUS_CHANGED:
_TransferGradientStopColor();
break;
default:
BView::MessageReceived(message);
break;
}
}
BSize
StyleView::MinSize()
{
BSize minSize = BView::MinSize();
minSize.width = fGradientControl->MinSize().width + 10;
return minSize;
}
void
StyleView::ObjectChanged(const Observable* object)
{
if (!fStyle)
return;
Gradient* controlGradient = fGradientControl->Gradient();
if (object == controlGradient) {
if (!fGradient.IsSet())
return;
if (fIgnoreControlGradientNotifications)
return;
fIgnoreControlGradientNotifications = true;
if (!fGradient->ColorStepsAreEqual(*controlGradient)) {
controlGradient->SetTransform(*fGradient);
if (fCommandStack) {
fCommandStack->Perform(
new (nothrow) SetGradientCommand(
fStyle, controlGradient));
} else {
*fGradient = *controlGradient;
}
_TransferGradientStopColor();
}
fIgnoreControlGradientNotifications = false;
} else if (object == fGradient) {
if (!fGradient->ColorStepsAreEqual(*controlGradient)) {
fGradientControl->SetGradient(fGradient);
_MarkType(fGradientType->Menu(), fGradient->Type());
_TransferGradientStopColor();
}
} else if (object == fStyle) {
_SetGradient(fStyle->Gradient(), false, true);
if (fCurrentColor && !fStyle->Gradient())
fCurrentColor->SetColor(fStyle->Color());
} else if (object == fCurrentColor) {
if (!fIgnoreCurrentColorNotifications)
_AdoptCurrentColor(fCurrentColor->Color());
}
}
void
StyleView::SetStyle(Style* style)
{
if (fStyle == style)
return;
if (fStyle) {
fStyle->RemoveObserver(this);
fStyle->ReleaseReference();
}
fStyle = style;
Gradient* gradient = NULL;
if (fStyle) {
fStyle->AcquireReference();
fStyle->AddObserver(this);
gradient = fStyle->Gradient();
if (fCurrentColor && !gradient)
fCurrentColor->SetColor(fStyle->Color());
fStyleType->SetEnabled(true);
} else
fStyleType->SetEnabled(false);
_SetGradient(gradient, true);
}
void
StyleView::SetCommandStack(CommandStack* stack)
{
fCommandStack = stack;
}
void
StyleView::SetCurrentColor(CurrentColor* color)
{
if (fCurrentColor == color)
return;
if (fCurrentColor)
fCurrentColor->RemoveObserver(this);
fCurrentColor = color;
if (fCurrentColor)
fCurrentColor->AddObserver(this);
}
void
StyleView::_SetGradient(Gradient* gradient, bool forceControlUpdate,
bool sendMessage)
{
if (!forceControlUpdate && gradient == fGradient)
return;
if (fGradient.IsSet())
fGradient->RemoveObserver(this);
fGradient.SetTo(gradient);
if (fGradient.IsSet()) {
fGradient->AddObserver(this);
}
if (fGradient.IsSet()) {
fGradientControl->SetEnabled(true);
fGradientControl->SetGradient(fGradient);
fGradientType->SetEnabled(true);
_MarkType(fStyleType->Menu(), STYLE_TYPE_GRADIENT);
_MarkType(fGradientType->Menu(), fGradient->Type());
} else {
fGradientControl->SetEnabled(false);
fGradientType->SetEnabled(false);
_MarkType(fStyleType->Menu(), STYLE_TYPE_COLOR);
_MarkType(fGradientType->Menu(), -1);
}
if (sendMessage) {
BMessage message(MSG_STYLE_TYPE_CHANGED);
message.AddPointer("style", fStyle);
Window()->PostMessage(&message);
}
}
void
StyleView::_MarkType(BMenu* menu, int32 type) const
{
for (int32 i = 0; BMenuItem* item = menu->ItemAt(i); i++) {
BMessage* message = item->Message();
int32 t;
if (message->FindInt32("type", &t) == B_OK && t == type) {
if (!item->IsMarked())
item->SetMarked(true);
return;
}
}
}
void
StyleView::_SetStyleType(int32 type)
{
if (!fStyle)
return;
if (type == STYLE_TYPE_COLOR) {
if (fCommandStack) {
fCommandStack->Perform(
new (nothrow) SetGradientCommand(fStyle, NULL));
} else {
fStyle->SetGradient(NULL);
}
} else if (type == STYLE_TYPE_GRADIENT) {
if (fCommandStack) {
Gradient gradient(true);
gradient.AddColor(fStyle->Color(), 0);
gradient.AddColor(fStyle->Color(), 1);
fCommandStack->Perform(
new (nothrow) SetGradientCommand(fStyle, &gradient));
} else {
fStyle->SetGradient(fGradientControl->Gradient());
}
}
}
void
StyleView::_SetGradientType(int32 type)
{
fGradientControl->Gradient()->SetType((gradients_type)type);
}
void
StyleView::_AdoptCurrentColor(rgb_color color)
{
if (!fStyle)
return;
if (fGradient.IsSet()) {
if (fGradientControl->IsFocus()) {
fGradientControl->SetCurrentStop(color);
}
} else {
if (fCommandStack) {
fCommandStack->Perform(
new (nothrow) SetColorCommand(fStyle, color));
} else {
fStyle->SetColor(color);
}
}
}
void
StyleView::_TransferGradientStopColor()
{
if (fCurrentColor && fGradientControl->IsFocus()) {
rgb_color color;
if (fGradientControl->GetCurrentStop(&color)) {
fIgnoreCurrentColorNotifications = true;
fCurrentColor->SetColor(color);
fIgnoreCurrentColorNotifications = false;
}
}
}