2 * Copyright (c) 1999-2000, Eric Moon.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions, and the following disclaimer.
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.
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.
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.
32 // ValControlDigitSegment.cpp
34 #include "ValControlDigitSegment.h"
35 #include "ValControl.h"
37 #include "NumericValControl.h"
45 __USE_CORTEX_NAMESPACE
47 // -------------------------------------------------------- //
48 // constants/static stuff
49 // -------------------------------------------------------- //
51 const float ValControlDigitSegment::s_widthTrim
= -2;
53 const BFont
* ValControlDigitSegment::s_cachedFont
= 0;
54 float ValControlDigitSegment::s_cachedDigitWidth
= 0.0;
56 // -------------------------------------------------------- //
57 // ctor/dtor/accessors
58 // -------------------------------------------------------- //
60 ValControlDigitSegment::ValControlDigitSegment(
64 display_flags flags
) :
66 ValControlSegment(SOLID_UNDERLINE
),
68 m_digitCount(digitCount
),
71 m_scaleFactor(scaleFactor
),
74 m_minusSignWidth(0.0),
77 m_negativeVisible(negativeVisible
) {}
79 ValControlDigitSegment::~ValControlDigitSegment() {}
81 uint16
ValControlDigitSegment::digitCount() const {
85 int16
ValControlDigitSegment::scaleFactor() const {
89 int64
ValControlDigitSegment::value() const {
93 // -------------------------------------------------------- //
95 // -------------------------------------------------------- //
97 // revised setValue() 18sep99: now sets the
98 // value of the displayed digits ONLY.
100 // a tad simpler. the old setValue() is provided for giggles.
102 void ValControlDigitSegment::setValue(
108 m_negative
== negative
)
112 m_negative
= negative
;
117 //void ValControlDigitSegment::setValue(double dfValue) {
119 // printf("seg[%d]::setValue(%.12f)\n", m_digitCount, dfValue);
121 // // convert possibly-negative value into absolute value and
123 // bool m_bWasNegative = m_negative;
124 // m_negative = (m_negativeVisible && dfValue < 0.0);
125 // dfValue = fabs(dfValue);
127 // // prepare to scale the value to fit the digits this segment
129 // bool bMult = m_scaleFactor < 0;
130 // int64 nLowPow = m_scaleFactor ? (int64)pow(10.0, abs(m_scaleFactor)) : 1;
131 // int64 nHighPow = (int64)pow(10.0, m_digitCount);
133 //// printf(" lowPow %Ld, highPow %Ld\n", nLowPow, nHighPow);
135 // double dfTemp = bMult ? dfValue * nLowPow : dfValue / nLowPow;
136 //// printf(" -> %.8lf\n", dfTemp);
139 // if(m_scaleFactor < 0) {
140 // // really ugly rounding business: there must be a cleaner
141 // // way to do this...
142 // double dfC = ceil(dfTemp);
143 // double dfCDelta = dfC-dfTemp;
144 // double dfF = floor(dfTemp);
145 // double dfFDelta = dfTemp - dfF;
147 // nLocal = (int64)((dfCDelta < dfFDelta) ? dfC : dfF);
150 // nLocal = (int64)dfTemp;
152 //// printf(" -> %Ld\n", nLocal);
153 // nLocal %= nHighPow;
154 //// printf(" -> %Ld\n", nLocal);
156 // if(nLocal != m_value || m_negative != m_bWasNegative) {
162 // -------------------------------------------------------- //
163 // ValControlSegment impl.
164 // -------------------------------------------------------- //
166 ValCtrlLayoutEntry
ValControlDigitSegment::makeLayoutEntry() {
167 return ValCtrlLayoutEntry(this, ValCtrlLayoutEntry::SEGMENT_ENTRY
);
170 float ValControlDigitSegment::handleDragUpdate(
173 int64 units
= (int64
)(distance
/ dragScaleFactor());
174 float remaining
= distance
;
177 remaining
= fmod(distance
, dragScaleFactor());
179 // +++++ echk [23aug99] -- is this the only way?
180 NumericValControl
* numericParent
= dynamic_cast<NumericValControl
*>(parent());
181 ASSERT(numericParent
);
183 // adjust value for parent:
184 // dfUnits = floor(dfUnits);
185 // dfUnits *= pow(10.0, m_scaleFactor);
189 // "offset: %.8f\n", dfUnits));
191 // numericParent->offsetValue(dfUnits);
193 numericParent
->offsetSegmentValue(this, units
);
196 // return 'unused pixels'
200 void ValControlDigitSegment::mouseReleased() {
204 // -------------------------------------------------------- //
206 // -------------------------------------------------------- //
208 void ValControlDigitSegment::Draw(BRect updateRect
) {
211 // "### ValControlDigitSegment::Draw()\n"));
216 BBitmap
* pBufferBitmap
= parent()->backBuffer();
217 BView
* pView
= pBufferBitmap
? parent()->backBufferView() : this;
219 pBufferBitmap
->Lock();
221 // rgb_color white = {255,255,255,255};
222 rgb_color black
= {0,0,0,255};
223 rgb_color disabled
= tint_color(black
, B_LIGHTEN_2_TINT
);
224 rgb_color viewColor
= ViewColor();
230 // "# ValControlDigitSegment::Draw(%.1f,%.1f,%.1f,%.1f) %s\n"
231 // " frame(%.1f,%.1f,%.1f,%.1f)\n\n",
232 // updateRect.left, updateRect.top, updateRect.right, updateRect.bottom,
233 // pBufferBitmap ? "(BUFFERED)" : "(DIRECT)",
234 // Frame().left, Frame().top, Frame().right, Frame().bottom));
236 float digitWidth
= MaxDigitWidth(m_font
);
238 p
.x
= b
.right
- digitWidth
;
241 // // clear background
242 // pView->SetHighColor(white);
243 // pView->FillRect(b);
245 // draw a digit at a time, right to left (low->high)
246 pView
->SetFont(m_font
);
247 if(parent()->IsEnabled()) {
249 pView
->SetHighColor(black
);
252 pView
->SetHighColor(disabled
);
255 pView
->SetLowColor(viewColor
);
257 int64 cur
= abs(m_value
);
260 digit
< m_digitCount
;
261 digit
++, cur
/= 10, p
.x
-= (digitWidth
+m_digitPadding
)) {
263 uint8 digitValue
= (uint8
)(cur
% 10);
264 if(digit
&& !(m_flags
& ZERO_FILL
) && !cur
)
266 pView
->DrawChar('0' + digitValue
, p
);
267 // PRINT(("ch(%.1f,%.1f): %c\n", p.x, p.y, '0' + digitValue));
272 p
.x
+= (digitWidth
-m_minusSignWidth
);
273 pView
->DrawChar('-', p
);
279 DrawBitmap(parent()->backBuffer(), b
, b
);
280 pBufferBitmap
->Unlock();
283 _inherited::Draw(updateRect
);
286 // must have parent at this point +++++
287 void ValControlDigitSegment::GetPreferredSize(float* pWidth
, float* pHeight
) {
289 // // font initialized?
294 *pWidth
= prefWidth();
295 *pHeight
= prefHeight();
298 // +++++ need a way to return an overlap amount?
299 // -> underline should extend a pixel to the right.
300 float ValControlDigitSegment::prefWidth() const {
303 float width
= (m_digitCount
*MaxDigitWidth(m_font
)) +
304 ((m_digitCount
- 1)*m_digitPadding
);
305 if(m_negativeVisible
)
306 width
+= (m_minusSignWidth
+ m_digitPadding
);
311 float ValControlDigitSegment::prefHeight() const {
313 return m_fontHeight
.ascent
+ m_fontHeight
.descent
+ m_fontHeight
.leading
;
316 // do any font-related layout work
317 void ValControlDigitSegment::fontChanged(
320 // "* ValControlDigitSegment::fontChanged()\n"));
324 m_font
->GetHeight(&m_fontHeight
);
327 m_yOffset
= parent()->baselineOffset();
329 m_minusSignWidth
= m_font
->StringWidth(&c
, 1) + s_widthTrim
;
331 // space between digits should be the same as space between
332 // segments, for consistent look:
333 m_digitPadding
= parent()->segmentPadding();
336 // -------------------------------------------------------- //
338 // -------------------------------------------------------- //
340 void ValControlDigitSegment::MessageReceived(BMessage
* pMsg
) {
347 case ValControl::M_SET_VALUE
:
348 err
= pMsg
->FindDouble("value", &fVal
);
350 setValue((int64
)fVal
, fVal
< 0);
353 case ValControl::M_GET_VALUE
: {
354 BMessage
reply(ValControl::M_VALUE
);
355 reply
.AddDouble("value", value());
356 pMsg
->SendReply(&reply
);
362 // -------------------------------------------------------- //
363 // archiving/instantiation
364 // -------------------------------------------------------- //
366 ValControlDigitSegment::ValControlDigitSegment(BMessage
* pArchive
) :
367 ValControlSegment(pArchive
),
369 m_digitPadding(0.0) {
372 status_t err
= pArchive
->FindInt16("digits", (int16
*)&m_digitCount
);
376 err
= pArchive
->FindInt64("value", &m_value
);
380 err
= pArchive
->FindInt16("scaleFactor", &m_scaleFactor
);
384 status_t
ValControlDigitSegment::Archive(BMessage
* pArchive
, bool bDeep
) const{
385 _inherited::Archive(pArchive
, bDeep
);
387 pArchive
->AddInt16("digits", m_digitCount
);
388 pArchive
->AddInt64("value", m_value
);
389 pArchive
->AddInt16("scaleFactor", m_scaleFactor
);
395 BArchivable
* ValControlDigitSegment::Instantiate(BMessage
* pArchive
) {
396 if(validate_instantiation(pArchive
, "ValControlDigitSegment"))
397 return new ValControlDigitSegment(pArchive
);
402 // -------------------------------------------------------- //
404 // -------------------------------------------------------- //
407 float ValControlDigitSegment::MaxDigitWidth(const BFont
* pFont
) {
409 if(s_cachedFont
== pFont
)
410 return s_cachedDigitWidth
;
412 s_cachedFont
= pFont
;
414 for(char c
= '0'; c
<= '9'; c
++) {
415 float fWidth
= pFont
->StringWidth(&c
, 1);
420 s_cachedDigitWidth
= ceil(fMax
+ s_widthTrim
);
421 return s_cachedDigitWidth
;
424 // END -- ValControlDigitSegment.cpp --