1/*
2 * Copyright (c) 1999-2000, Eric Moon.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions, and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions, and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * 3. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31
32// TipView.cpp
33
34#include "TipView.h"
35
36#include <Debug.h>
37#include <Window.h>
38#include <cmath>
39#include <cstring>
40
41using namespace std;
42
43__USE_CORTEX_NAMESPACE
44
45// -------------------------------------------------------- //
46// constants
47// -------------------------------------------------------- //
48
49const float TipView::s_xPad = 5.0;
50const float TipView::s_yPad = 2.0;
51
52// -------------------------------------------------------- //
53// *** dtor/ctors
54// -------------------------------------------------------- //
55
56TipView::~TipView() {}
57TipView::TipView() :
58	BView(
59		BRect(0,0,0,0),
60		"TipView",
61		B_FOLLOW_NONE,
62		B_WILL_DRAW|B_FRAME_EVENTS),
63	m_font(be_plain_font) {
64
65	_initColors();
66	_initFont();
67}
68
69// -------------------------------------------------------- //
70// *** operations
71// -------------------------------------------------------- //
72
73void TipView::setText(
74	const char*							text) {
75
76	_setText(text);
77}
78
79// -------------------------------------------------------- //
80// *** BView
81// -------------------------------------------------------- //
82
83// Adapted from c.lenz' ToolTipView::Draw()
84void TipView::Draw(
85	BRect										updateRect) {
86
87	BRect r = Bounds();
88
89	// Draw border and fill
90	SetDrawingMode(B_OP_ALPHA);
91	SetHighColor(m_borderLoColor);
92	StrokeLine(r.LeftBottom(), r.RightBottom());
93	StrokeLine(r.RightTop(), r.RightBottom());
94	SetHighColor(m_borderHiColor);
95	StrokeLine(r.LeftTop(), r.RightTop());
96	StrokeLine(r.LeftTop(), r.LeftBottom());
97	SetHighColor(m_viewColor);
98	SetDrawingMode(B_OP_ALPHA);
99	r.InsetBy(1.0, 1.0);
100	FillRect(r);
101
102	// Draw text
103	SetDrawingMode(B_OP_OVER);
104	SetHighColor(m_textColor);
105
106	BPoint p = m_offset;
107	for(uint32 n = 0; n < m_lineSet.size(); ++n) {
108
109		uint32 from = m_lineSet[n];
110		uint32 to = (n < m_lineSet.size()-1) ? m_lineSet[n+1]-1 :
111			m_text.Length();
112
113		if(to > from)
114			DrawString(
115				m_text.String() + from,
116				to - from,
117				p);
118
119		p.y += (m_fontHeight.ascent + m_fontHeight.descent + m_fontHeight.leading);
120	}
121}
122
123void TipView::FrameResized(
124	float										width,
125	float										height) {
126
127	_inherited::FrameResized(width, height);
128	_updateLayout(width, height);
129	Invalidate();
130}
131
132void TipView::GetPreferredSize(
133	float*									outWidth,
134	float*									outHeight) {
135
136//	*outWidth = ceil(m_font.StringWidth(m_text.String()) + s_xPad*2);
137	*outWidth = ceil(_maxTextWidth() + s_xPad*2);
138	*outHeight = ceil(_textHeight() + s_yPad*2);
139}
140
141// -------------------------------------------------------- //
142// implementation
143// -------------------------------------------------------- //
144
145void _make_color(
146	rgb_color*							outColor,
147	uint8										red,
148	uint8										green,
149	uint8										blue,
150	uint8										alpha=255);
151void _make_color(
152	rgb_color*							outColor,
153	uint8										red,
154	uint8										green,
155	uint8										blue,
156	uint8										alpha) {
157	outColor->red = red;
158	outColor->green = green;
159	outColor->blue = blue;
160	outColor->alpha = alpha;
161}
162
163void TipView::_initColors() {
164
165	SetViewColor(B_TRANSPARENT_COLOR);
166
167	_make_color(&m_textColor, 0, 0, 0, 255);
168	_make_color(&m_borderHiColor, 0, 0, 0, 255 /*196*/);
169	_make_color(&m_borderLoColor, 0, 0, 0, 255 /*196*/);
170	_make_color(&m_viewColor, 255, 255, 240, 255 /*216*/);
171}
172
173void TipView::_initFont() {
174
175	SetFont(&m_font);
176	m_font.GetHeight(&m_fontHeight);
177}
178
179void TipView::_updateLayout(
180	float										width,
181	float										height) {
182
183	// center text
184	m_offset.x = (width - _maxTextWidth()) / 2;
185
186	m_offset.y = (height - _textHeight()) / 2;
187	m_offset.y += m_fontHeight.ascent;
188}
189
190void TipView::_setText(
191	const char*							text) {
192
193	ASSERT(text);
194
195	m_lineSet.clear();
196	m_text = text;
197
198	// skip leading newlines
199	int32 n = 0;
200	while(n < m_text.Length() && m_text[n] == '\n')
201		++n;
202
203	// mark first line
204	m_lineSet.push_back(n);
205
206	// break following lines
207	while(n < m_text.Length()) {
208		int32 nextBreak = m_text.FindFirst('\n', n);
209		// no more line breaks?
210		if(nextBreak < n)
211			break;
212		n = nextBreak + 1;
213		m_lineSet.push_back(n);
214	}
215}
216
217float TipView::_maxTextWidth() {
218	float max = 0.0;
219	for(uint32 n = 0; n < m_lineSet.size(); ++n) {
220		uint32 from = m_lineSet[n];
221		uint32 to = (n < m_lineSet.size()-1) ? m_lineSet[n+1]-1 :
222			m_text.Length();
223		float lineWidth = m_font.StringWidth(
224			m_text.String() + from,
225			to - from);
226		if(lineWidth > max)
227			max = lineWidth;
228	}
229	return max;
230}
231
232float TipView::_textHeight() {
233	float height = m_fontHeight.ascent + m_fontHeight.descent;
234	if(m_lineSet.size() > 1)
235		height += (m_lineSet.size()-1) *
236			(m_fontHeight.ascent + m_fontHeight.descent + m_fontHeight.leading);
237
238	return height;
239}
240
241// END -- TipView.cpp --
242