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 "OptionValueView.h"
10
11#include <stdio.h>
12
13#include <Font.h>
14#include <MenuItem.h>
15#include <Message.h>
16#include <PopUpMenu.h>
17#include <Region.h>
18
19enum {
20	MSG_OPTION_CHANGED = 'opch',
21};
22
23// constructor
24OptionValueView::OptionValueView(OptionProperty* property)
25	: PropertyEditorView(),
26	  fProperty(property),
27	  fCurrentOption(""),
28	  fEnabled(true)
29{
30	if (fProperty)
31		fProperty->GetCurrentOption(&fCurrentOption);
32}
33
34// destructor
35OptionValueView::~OptionValueView()
36{
37}
38
39// Draw
40void
41OptionValueView::Draw(BRect updateRect)
42{
43	BRect b(Bounds());
44	// focus indication
45	if (IsFocus()) {
46		SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
47		StrokeRect(b);
48		b.InsetBy(1.0, 1.0);
49		BRegion clipping;
50		clipping.Include(b);
51		ConstrainClippingRegion(&clipping);
52		b.left --;
53	}
54	// background
55	FillRect(b, B_SOLID_LOW);
56
57	rgb_color labelColor = LowColor();
58	if (fEnabled)
59		labelColor = tint_color(labelColor, B_DARKEN_MAX_TINT);
60	else
61		labelColor = tint_color(labelColor, B_DISABLED_LABEL_TINT);
62
63	SetHighColor(labelColor);
64
65	b.InsetBy(2.0, 1.0);
66
67	float center = floorf(b.top + b.Height() / 2.0);
68
69	BPoint arrow[3];
70	arrow[0] = BPoint(b.left, center - 3.0);
71	arrow[1] = BPoint(b.left, center + 3.0);
72	arrow[2] = BPoint(b.left + 3.0, center);
73
74	FillPolygon(arrow, 3);
75
76	b.left += 6.0;
77
78	BFont font;
79	GetFont(&font);
80
81	font_height fh;
82	font.GetHeight(&fh);
83
84	BString truncated(fCurrentOption);
85	font.TruncateString(&truncated, B_TRUNCATE_END, b.Width());
86
87	DrawString(fCurrentOption.String(), BPoint(b.left, floorf(center + fh.ascent / 2.0)));
88}
89
90// FrameResized
91void
92OptionValueView::FrameResized(float width, float height)
93{
94/*	float radius = ceilf((height - 6.0) / 2.0);
95	float centerX = floorf(Bounds().left + width / 2.0);
96	float centerY = floorf(Bounds().top + height / 2.0);
97	fCheckBoxRect.Set(centerX - radius, centerY - radius,
98					  centerX + radius, centerY + radius);*/
99}
100
101// MakeFocus
102void
103OptionValueView::MakeFocus(bool focused)
104{
105	PropertyEditorView::MakeFocus(focused);
106	Invalidate();
107}
108
109// MessageReceived
110void
111OptionValueView::MessageReceived(BMessage* message)
112{
113	switch (message->what) {
114		case MSG_OPTION_CHANGED:
115			if (fProperty) {
116				int32 id;
117				if (message->FindInt32("id", &id) >= B_OK) {
118					fProperty->SetCurrentOptionID(id);
119					ValueChanged();
120				}
121			}
122			break;
123		default:
124			PropertyEditorView::MessageReceived(message);
125			break;
126	}
127}
128
129// MouseDown
130void
131OptionValueView::MouseDown(BPoint where)
132{
133	if (BView* parent = Parent())
134		parent->MouseDown(ConvertToParent(where));
135
136	if (fProperty) {
137		BPopUpMenu* menu = new BPopUpMenu("option popup", false, false);
138		BString name;
139		int32 id;
140		for (int32 i = 0; fProperty->GetOption(i, &name, &id); i++) {
141			BMessage* message = new BMessage(MSG_OPTION_CHANGED);
142			message->AddInt32("id", id);
143			BMenuItem* item = new BMenuItem(name.String(), message);
144			menu->AddItem(item);
145			if (id == fProperty->CurrentOptionID())
146				item->SetMarked(true);
147		}
148		menu->SetTargetForItems(this);
149		menu->SetAsyncAutoDestruct(true);
150		menu->SetFont(be_plain_font);
151		menu->SetEnabled(fEnabled);
152
153		where = ConvertToScreen(where);
154		BRect mouseRect(where, where);
155		mouseRect.InsetBy(-10.0, -10.0);
156		where += BPoint(5.0, 5.0);
157		menu->Go(where, true, false, mouseRect, true);
158	}
159}
160
161// KeyDown
162void
163OptionValueView::KeyDown(const char* bytes, int32 numBytes)
164{
165	bool handled = fEnabled;
166	if (fEnabled && numBytes > 0) {
167		switch (bytes[0]) {
168			case B_LEFT_ARROW:
169			case B_UP_ARROW:
170				fProperty->SetOptionAtOffset(-1);
171				ValueChanged();
172				break;
173
174			case B_RIGHT_ARROW:
175			case B_DOWN_ARROW:
176				fProperty->SetOptionAtOffset(1);
177				ValueChanged();
178				break;
179			default:
180				handled = false;
181				break;
182		}
183	}
184	if (!handled)
185		PropertyEditorView::KeyDown(bytes, numBytes);
186}
187
188// SetEnabled
189void
190OptionValueView::SetEnabled(bool enabled)
191{
192	if (fEnabled != enabled) {
193		fEnabled = enabled;
194		Invalidate();
195	}
196}
197
198// ValueChanged
199void
200OptionValueView::ValueChanged()
201{
202	if (fProperty) {
203		fProperty->GetCurrentOption(&fCurrentOption);
204		BRect b(Bounds());
205		b.InsetBy(1.0, 1.0);
206		b.left += 5.0;
207		Invalidate(b);
208	}
209	PropertyEditorView::ValueChanged();
210}
211
212// AdoptProperty
213bool
214OptionValueView::AdoptProperty(Property* property)
215{
216	OptionProperty* p = dynamic_cast<OptionProperty*>(property);
217	if (p) {
218		BString currentOption;
219		p->GetCurrentOption(&currentOption);
220		if (currentOption != fCurrentOption) {
221			fCurrentOption = currentOption;
222			BRect b(Bounds());
223			b.InsetBy(1.0, 1.0);
224			b.left += 5.0;
225			Invalidate(b);
226		}
227		fProperty = p;
228		return true;
229	}
230	return false;
231}
232
233// GetProperty
234Property*
235OptionValueView::GetProperty() const
236{
237	return fProperty;
238}
239
240