repository_infos: Enable automatic updates on the main Haiku repostiory.
[haiku.git] / src / apps / cortex / ValControl / ValControlDigitSegment.cpp
blob905d1a005b7788ed8521c798b3c3a3a746e5f1f9
1 /*
2 * Copyright (c) 1999-2000, Eric Moon.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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"
39 #include <Debug.h>
41 #include <math.h>
42 #include <stdlib.h>
43 #include <cstdio>
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(
61 uint16 digitCount,
62 int16 scaleFactor,
63 bool negativeVisible,
64 display_flags flags) :
66 ValControlSegment(SOLID_UNDERLINE),
68 m_digitCount(digitCount),
69 m_value(0),
70 m_negative(false),
71 m_scaleFactor(scaleFactor),
72 m_font(0),
73 m_yOffset(0.0),
74 m_minusSignWidth(0.0),
75 m_digitPadding(0.0),
76 m_flags(flags),
77 m_negativeVisible(negativeVisible) {}
79 ValControlDigitSegment::~ValControlDigitSegment() {}
81 uint16 ValControlDigitSegment::digitCount() const {
82 return m_digitCount;
85 int16 ValControlDigitSegment::scaleFactor() const {
86 return m_scaleFactor;
89 int64 ValControlDigitSegment::value() const {
90 return m_value;
93 // -------------------------------------------------------- //
94 // operations
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(
103 int64 value,
104 bool negative) {
107 value == m_value &&
108 m_negative == negative)
109 return;
111 m_value = value;
112 m_negative = negative;
113 Invalidate();
116 //// +++++
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
122 // // negative flag
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
128 // // represents
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);
138 // int64 nLocal;
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);
148 // }
149 // else
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) {
157 // m_value = nLocal;
158 // Invalidate();
159 // }
162 // -------------------------------------------------------- //
163 // ValControlSegment impl.
164 // -------------------------------------------------------- //
166 ValCtrlLayoutEntry ValControlDigitSegment::makeLayoutEntry() {
167 return ValCtrlLayoutEntry(this, ValCtrlLayoutEntry::SEGMENT_ENTRY);
170 float ValControlDigitSegment::handleDragUpdate(
171 float distance) {
173 int64 units = (int64)(distance / dragScaleFactor());
174 float remaining = distance;
176 if(units) {
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);
187 // // ++++++ 17sep99
188 // PRINT((
189 // "offset: %.8f\n", dfUnits));
191 // numericParent->offsetValue(dfUnits);
193 numericParent->offsetSegmentValue(this, units);
196 // return 'unused pixels'
197 return remaining;
200 void ValControlDigitSegment::mouseReleased() {
201 // +++++
204 // -------------------------------------------------------- //
205 // BView impl.
206 // -------------------------------------------------------- //
208 void ValControlDigitSegment::Draw(BRect updateRect) {
210 // PRINT((
211 // "### ValControlDigitSegment::Draw()\n"));
214 ASSERT(m_font);
216 BBitmap* pBufferBitmap = parent()->backBuffer();
217 BView* pView = pBufferBitmap ? parent()->backBufferView() : this;
218 if(pBufferBitmap)
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();
226 // +++++
228 BRect b = Bounds();
229 // PRINT((
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);
237 BPoint p;
238 p.x = b.right - digitWidth;
239 p.y = m_yOffset;
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);
250 } else {
252 pView->SetHighColor(disabled);
255 pView->SetLowColor(viewColor);
256 int16 digit;
257 int64 cur = abs(m_value);
259 for(digit = 0;
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)
265 break;
266 pView->DrawChar('0' + digitValue, p);
267 // PRINT(("ch(%.1f,%.1f): %c\n", p.x, p.y, '0' + digitValue));
270 if(m_negative) {
271 // draw minus sign
272 p.x += (digitWidth-m_minusSignWidth);
273 pView->DrawChar('-', p);
276 // paint buffer?
277 if(pBufferBitmap) {
278 pView->Sync();
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?
290 // if(!m_font) {
291 // initFont();
292 // }
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 {
301 ASSERT(m_font);
303 float width = (m_digitCount*MaxDigitWidth(m_font)) +
304 ((m_digitCount - 1)*m_digitPadding);
305 if(m_negativeVisible)
306 width += (m_minusSignWidth + m_digitPadding);
308 return width;
311 float ValControlDigitSegment::prefHeight() const {
312 ASSERT(m_font);
313 return m_fontHeight.ascent + m_fontHeight.descent + m_fontHeight.leading;
316 // do any font-related layout work
317 void ValControlDigitSegment::fontChanged(
318 const BFont* font) {
319 // PRINT((
320 // "* ValControlDigitSegment::fontChanged()\n"));
322 m_font = font;
324 m_font->GetHeight(&m_fontHeight);
326 ASSERT(parent());
327 m_yOffset = parent()->baselineOffset();
328 char c = '-';
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 // -------------------------------------------------------- //
337 // BHandler impl.
338 // -------------------------------------------------------- //
340 void ValControlDigitSegment::MessageReceived(BMessage* pMsg) {
342 double fVal;
343 status_t err;
345 switch(pMsg->what) {
347 case ValControl::M_SET_VALUE:
348 err = pMsg->FindDouble("value", &fVal);
349 ASSERT(err == B_OK);
350 setValue((int64)fVal, fVal < 0);
351 break;
353 case ValControl::M_GET_VALUE: {
354 BMessage reply(ValControl::M_VALUE);
355 reply.AddDouble("value", value());
356 pMsg->SendReply(&reply);
357 break;
362 // -------------------------------------------------------- //
363 // archiving/instantiation
364 // -------------------------------------------------------- //
366 ValControlDigitSegment::ValControlDigitSegment(BMessage* pArchive) :
367 ValControlSegment(pArchive),
368 m_font(0),
369 m_digitPadding(0.0) {
371 // #/digits
372 status_t err = pArchive->FindInt16("digits", (int16*)&m_digitCount);
373 ASSERT(err == B_OK);
375 // current value
376 err = pArchive->FindInt64("value", &m_value);
377 ASSERT(err == B_OK);
379 // scaling
380 err = pArchive->FindInt16("scaleFactor", &m_scaleFactor);
381 ASSERT(err == B_OK);
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);
391 return B_OK;
394 /* static */
395 BArchivable* ValControlDigitSegment::Instantiate(BMessage* pArchive) {
396 if(validate_instantiation(pArchive, "ValControlDigitSegment"))
397 return new ValControlDigitSegment(pArchive);
398 else
399 return 0;
402 // -------------------------------------------------------- //
403 // helpers
404 // -------------------------------------------------------- //
406 /*static*/
407 float ValControlDigitSegment::MaxDigitWidth(const BFont* pFont) {
408 ASSERT(pFont);
409 if(s_cachedFont == pFont)
410 return s_cachedDigitWidth;
412 s_cachedFont = pFont;
413 float fMax = 0.0;
414 for(char c = '0'; c <= '9'; c++) {
415 float fWidth = pFont->StringWidth(&c, 1);
416 if(fWidth > fMax)
417 fMax = fWidth;
420 s_cachedDigitWidth = ceil(fMax + s_widthTrim);
421 return s_cachedDigitWidth;
424 // END -- ValControlDigitSegment.cpp --