/*
* Copyright (c) 1999-2000, Eric Moon.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions, and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// ValControlDigitSegment.cpp
#include "ValControlDigitSegment.h"
#include "ValControl.h"
#include "NumericValControl.h"
#include <Debug.h>
#include <math.h>
#include <stdlib.h>
#include <cstdio>
__USE_CORTEX_NAMESPACE
// -------------------------------------------------------- //
// constants/static stuff
// -------------------------------------------------------- //
const float ValControlDigitSegment::s_widthTrim = -2;
const BFont* ValControlDigitSegment::s_cachedFont = 0;
float ValControlDigitSegment::s_cachedDigitWidth = 0.0;
// -------------------------------------------------------- //
// ctor/dtor/accessors
// -------------------------------------------------------- //
ValControlDigitSegment::ValControlDigitSegment(
uint16 digitCount,
int16 scaleFactor,
bool negativeVisible,
display_flags flags) :
ValControlSegment(SOLID_UNDERLINE),
m_digitCount(digitCount),
m_value(0),
m_negative(false),
m_scaleFactor(scaleFactor),
m_font(0),
m_yOffset(0.0),
m_minusSignWidth(0.0),
m_digitPadding(0.0),
m_flags(flags),
m_negativeVisible(negativeVisible) {}
ValControlDigitSegment::~ValControlDigitSegment() {}
uint16 ValControlDigitSegment::digitCount() const {
return m_digitCount;
}
int16 ValControlDigitSegment::scaleFactor() const {
return m_scaleFactor;
}
int64 ValControlDigitSegment::value() const {
return m_value;
}
// -------------------------------------------------------- //
// operations
// -------------------------------------------------------- //
// revised setValue() 18sep99: now sets the
// value of the displayed digits ONLY.
//
// a tad simpler. the old setValue() is provided for giggles.
//
void ValControlDigitSegment::setValue(
int64 value,
bool negative) {
if(
value == m_value &&
m_negative == negative)
return;
m_value = value;
m_negative = negative;
Invalidate();
}
//// +++++
//void ValControlDigitSegment::setValue(double dfValue) {
//
// printf("seg[%d]::setValue(%.12f)\n", m_digitCount, dfValue);
//
// // convert possibly-negative value into absolute value and
// // negative flag
// bool m_bWasNegative = m_negative;
// m_negative = (m_negativeVisible && dfValue < 0.0);
// dfValue = fabs(dfValue);
//
// // prepare to scale the value to fit the digits this segment
// // represents
// bool bMult = m_scaleFactor < 0;
// int64 nLowPow = m_scaleFactor ? (int64)pow(10.0, abs(m_scaleFactor)) : 1;
// int64 nHighPow = (int64)pow(10.0, m_digitCount);
//
//// printf(" lowPow %Ld, highPow %Ld\n", nLowPow, nHighPow);
//
// double dfTemp = bMult ? dfValue * nLowPow : dfValue / nLowPow;
//// printf(" -> %.8lf\n", dfTemp);
//
// int64 nLocal;
// if(m_scaleFactor < 0) {
// // really ugly rounding business: there must be a cleaner
// // way to do this...
// double dfC = ceil(dfTemp);
// double dfCDelta = dfC-dfTemp;
// double dfF = floor(dfTemp);
// double dfFDelta = dfTemp - dfF;
//
// nLocal = (int64)((dfCDelta < dfFDelta) ? dfC : dfF);
// }
// else
// nLocal = (int64)dfTemp;
//
//// printf(" -> %Ld\n", nLocal);
// nLocal %= nHighPow;
//// printf(" -> %Ld\n", nLocal);
//
// if(nLocal != m_value || m_negative != m_bWasNegative) {
// m_value = nLocal;
// Invalidate();
// }
//}
// -------------------------------------------------------- //
// ValControlSegment impl.
// -------------------------------------------------------- //
ValCtrlLayoutEntry ValControlDigitSegment::makeLayoutEntry() {
return ValCtrlLayoutEntry(this, ValCtrlLayoutEntry::SEGMENT_ENTRY);
}
float ValControlDigitSegment::handleDragUpdate(
float distance) {
int64 units = (int64)(distance / dragScaleFactor());
float remaining = distance;
if(units) {
remaining = fmod(distance, dragScaleFactor());
// +++++ echk [23aug99] -- is this the only way?
NumericValControl* numericParent = dynamic_cast<NumericValControl*>(parent());
ASSERT(numericParent);
// adjust value for parent:
// dfUnits = floor(dfUnits);
// dfUnits *= pow(10.0, m_scaleFactor);
//
// // ++++++ 17sep99
// PRINT((
// "offset: %.8f\n", dfUnits));
//
// numericParent->offsetValue(dfUnits);
numericParent->offsetSegmentValue(this, units);
}
// return 'unused pixels'
return remaining;
}
void ValControlDigitSegment::mouseReleased() {
// +++++
}
// -------------------------------------------------------- //
// BView impl.
// -------------------------------------------------------- //
void ValControlDigitSegment::Draw(BRect updateRect) {
// PRINT((
// "### ValControlDigitSegment::Draw()\n"));
//
ASSERT(m_font);
BBitmap* pBufferBitmap = parent()->backBuffer();
BView* pView = pBufferBitmap ? parent()->backBufferView() : this;
if(pBufferBitmap)
pBufferBitmap->Lock();
// rgb_color white = {255,255,255,255};
rgb_color black = {0,0,0,255};
rgb_color disabled = tint_color(black, B_LIGHTEN_2_TINT);
rgb_color viewColor = ViewColor();
// +++++
BRect b = Bounds();
// PRINT((
// "# ValControlDigitSegment::Draw(%.1f,%.1f,%.1f,%.1f) %s\n"
// " frame(%.1f,%.1f,%.1f,%.1f)\n\n",
// updateRect.left, updateRect.top, updateRect.right, updateRect.bottom,
// pBufferBitmap ? "(BUFFERED)" : "(DIRECT)",
// Frame().left, Frame().top, Frame().right, Frame().bottom));
float digitWidth = MaxDigitWidth(m_font);
BPoint p;
p.x = b.right - digitWidth;
p.y = m_yOffset;
// // clear background
// pView->SetHighColor(white);
// pView->FillRect(b);
// draw a digit at a time, right to left (low->high)
pView->SetFont(m_font);
if(parent()->IsEnabled()) {
pView->SetHighColor(black);
} else {
pView->SetHighColor(disabled);
}
pView->SetLowColor(viewColor);
int16 digit;
int64 cur = abs(m_value);
for(digit = 0;
digit < m_digitCount;
digit++, cur /= 10, p.x -= (digitWidth+m_digitPadding)) {
uint8 digitValue = (uint8)(cur % 10);
if(digit && !(m_flags & ZERO_FILL) && !cur)
break;
pView->DrawChar('0' + digitValue, p);
// PRINT(("ch(%.1f,%.1f): %c\n", p.x, p.y, '0' + digitValue));
}
if(m_negative) {
// draw minus sign
p.x += (digitWidth-m_minusSignWidth);
pView->DrawChar('-', p);
}
// paint buffer?
if(pBufferBitmap) {
pView->Sync();
DrawBitmap(parent()->backBuffer(), b, b);
pBufferBitmap->Unlock();
}
_inherited::Draw(updateRect);
}
// must have parent at this point +++++
void ValControlDigitSegment::GetPreferredSize(float* pWidth, float* pHeight) {
// // font initialized?
// if(!m_font) {
// initFont();
// }
*pWidth = prefWidth();
*pHeight = prefHeight();
}
// +++++ need a way to return an overlap amount?
// -> underline should extend a pixel to the right.
float ValControlDigitSegment::prefWidth() const {
ASSERT(m_font);
float width = (m_digitCount*MaxDigitWidth(m_font)) +
((m_digitCount - 1)*m_digitPadding);
if(m_negativeVisible)
width += (m_minusSignWidth + m_digitPadding);
return width;
}
float ValControlDigitSegment::prefHeight() const {
ASSERT(m_font);
return m_fontHeight.ascent + m_fontHeight.descent + m_fontHeight.leading;
}
// do any font-related layout work
void ValControlDigitSegment::fontChanged(
const BFont* font) {
// PRINT((
// "* ValControlDigitSegment::fontChanged()\n"));
m_font = font;
m_font->GetHeight(&m_fontHeight);
ASSERT(parent());
m_yOffset = parent()->baselineOffset();
char c = '-';
m_minusSignWidth = m_font->StringWidth(&c, 1) + s_widthTrim;
// space between digits should be the same as space between
// segments, for consistent look:
m_digitPadding = parent()->segmentPadding();
}
// -------------------------------------------------------- //
// BHandler impl.
// -------------------------------------------------------- //
void ValControlDigitSegment::MessageReceived(BMessage* pMsg) {
double fVal;
switch(pMsg->what) {
case ValControl::M_SET_VALUE:
pMsg->FindDouble("value", &fVal);
setValue((int64)fVal, fVal < 0);
break;
case ValControl::M_GET_VALUE: {
BMessage reply(ValControl::M_VALUE);
reply.AddDouble("value", value());
pMsg->SendReply(&reply);
break;
}
}
}
// -------------------------------------------------------- //
// archiving/instantiation
// -------------------------------------------------------- //
ValControlDigitSegment::ValControlDigitSegment(BMessage* pArchive) :
ValControlSegment(pArchive),
m_font(0),
m_digitPadding(0.0) {
// #/digits
status_t err = pArchive->FindInt16("digits", (int16*)&m_digitCount);
ASSERT(err == B_OK);
// current value
err = pArchive->FindInt64("value", &m_value);
ASSERT(err == B_OK);
// scaling
err = pArchive->FindInt16("scaleFactor", &m_scaleFactor);
ASSERT(err == B_OK);
}
status_t ValControlDigitSegment::Archive(BMessage* pArchive, bool bDeep) const{
_inherited::Archive(pArchive, bDeep);
pArchive->AddInt16("digits", m_digitCount);
pArchive->AddInt64("value", m_value);
pArchive->AddInt16("scaleFactor", m_scaleFactor);
return B_OK;
}
/* static */
BArchivable* ValControlDigitSegment::Instantiate(BMessage* pArchive) {
if(validate_instantiation(pArchive, "ValControlDigitSegment"))
return new ValControlDigitSegment(pArchive);
else
return 0;
}
// -------------------------------------------------------- //
// helpers
// -------------------------------------------------------- //
/*static*/
float ValControlDigitSegment::MaxDigitWidth(const BFont* pFont) {
ASSERT(pFont);
if(s_cachedFont == pFont)
return s_cachedDigitWidth;
s_cachedFont = pFont;
float fMax = 0.0;
for(char c = '0'; c <= '9'; c++) {
float fWidth = pFont->StringWidth(&c, 1);
if(fWidth > fMax)
fMax = fWidth;
}
s_cachedDigitWidth = ceil(fMax + s_widthTrim);
return s_cachedDigitWidth;
}
// END -- ValControlDigitSegment.cpp --
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: m_negative, m_fontHeight, m_yOffset, m_minusSignWidth, m_flags, m_negativeVisible.
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: m_fontHeight.