btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / apps / cortex / ValControl / ValControl.cpp
blobcf2c1b0d4f02cd5325898399e11eeecc886bdf71
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 // ValControl.cpp
34 #include "ValControl.h"
35 #include "ValControlSegment.h"
37 #include "TextControlFloater.h"
39 #include <Debug.h>
40 #include <String.h>
41 #include <Window.h>
43 #include <algorithm>
44 #include <functional>
45 #include <cstdio>
47 using namespace std;
49 __USE_CORTEX_NAMESPACE
52 const float ValControl::fSegmentPadding = 2.0;
54 // the decimal point covers one more pixel x and y-ward:
55 const float ValControl::fDecimalPointWidth = 2.0;
56 const float ValControl::fDecimalPointHeight = 2.0;
59 /*protected*/
60 ValControl::ValControl(BRect frame, const char* name, const char* label,
61 BMessage* message, align_mode alignMode, align_flags alignFlags,
62 update_mode updateMode, bool backBuffer)
63 : BControl(frame, name, label, message, B_FOLLOW_TOP|B_FOLLOW_LEFT,
64 B_WILL_DRAW|B_FRAME_EVENTS),
65 fDirty(true),
66 fUpdateMode(updateMode),
67 fLabelFont(be_bold_font),
68 fValueFont(be_bold_font),
69 fAlignMode(alignMode),
70 fAlignFlags(alignFlags),
71 fOrigBounds(Bounds()),
72 fHaveBackBuffer(backBuffer),
73 fBackBuffer(NULL),
74 fBackBufferView(NULL)
76 if (fHaveBackBuffer)
77 _AllocBackBuffer(frame.Width(), frame.Height());
79 // m_font.SetSize(13.0);
80 // rgb_color red = {255,0,0,255};
81 // SetViewColor(red);
85 ValControl::~ValControl()
87 delete fBackBuffer;
91 ValControl::update_mode
92 ValControl::updateMode() const
94 return fUpdateMode;
98 void
99 ValControl::setUpdateMode(update_mode mode)
101 fUpdateMode = mode;
105 const BFont*
106 ValControl::labelFont() const
108 return &fLabelFont;
112 void
113 ValControl::setLabelFont(const BFont* labelFont)
115 fLabelFont = labelFont;
116 // inform label segments
117 _InvalidateAll();
121 const BFont*
122 ValControl::valueFont() const
124 return &fValueFont;
128 void
129 ValControl::setValueFont(const BFont* valueFont)
131 fValueFont = valueFont;
133 // inform value segments
134 for (int n = CountEntries(); n > 0; --n) {
135 const ValCtrlLayoutEntry& e = _EntryAt(n-1);
136 if (e.type != ValCtrlLayoutEntry::SEGMENT_ENTRY)
137 continue;
139 ValControlSegment* s = dynamic_cast<ValControlSegment*>(e.pView);
140 ASSERT(s);
141 s->SetFont(&fValueFont);
142 s->fontChanged(&fValueFont);
147 float
148 ValControl::baselineOffset() const
150 font_height h;
151 be_plain_font->GetHeight(&h);
152 return ceil(h.ascent);
156 float
157 ValControl::segmentPadding() const
159 return fSegmentPadding;
163 BView*
164 ValControl::backBufferView() const
166 return fBackBufferView;
170 BBitmap*
171 ValControl::backBuffer() const
173 return fBackBuffer;
177 void
178 ValControl::dump()
180 #if defined(DEBUG)
181 BRect f = Frame();
183 PRINT((
184 "*** ValControl::dump():\n"
185 " FRAME (%.1f,%.1f)-(%.1f,%.1f)\n"
186 " ENTRIES:\n",
187 f.left, f.top, f.right, f.bottom));
189 for (layout_set::const_iterator it = fLayoutSet.begin();
190 it != fLayoutSet.end(); ++it) {
191 const ValCtrlLayoutEntry& e = *it;
192 switch (e.type) {
193 case ValCtrlLayoutEntry::SEGMENT_ENTRY:
194 PRINT((" Segment "));
195 break;
197 case ValCtrlLayoutEntry::VIEW_ENTRY:
198 PRINT((" View "));
199 break;
201 case ValCtrlLayoutEntry::DECIMAL_POINT_ENTRY:
202 PRINT((" Decimal Point "));
203 break;
205 default:
206 PRINT((" ??? "));
207 break;
210 PRINT(("\n cached frame (%.1f,%.1f)-(%.1f,%.1f) + pad(%.1f)\n",
211 e.frame.left, e.frame.top, e.frame.right, e.frame.bottom,
212 e.fPadding));
214 if (e.type == ValCtrlLayoutEntry::SEGMENT_ENTRY
215 || e.type == ValCtrlLayoutEntry::VIEW_ENTRY) {
216 if (e.pView) {
217 PRINT((" real frame (%.1f,%.1f)-(%.1f,%.1f)\n\n",
218 e.pView->Frame().left, e.pView->Frame().top,
219 e.pView->Frame().right, e.pView->Frame().bottom));
220 } else
221 PRINT((" (no view!)\n\n"));
224 PRINT(("\n"));
225 #endif
229 void
230 ValControl::SetEnabled(bool enabled)
232 // redraw if enabled-state changes
233 _Inherited::SetEnabled(enabled);
235 _InvalidateAll();
239 void
240 ValControl::_InvalidateAll()
242 Invalidate();
243 int c = CountChildren();
244 for (int n = 0; n < c; ++n)
245 ChildAt(n)->Invalidate();
249 void
250 ValControl::AttachedToWindow()
252 // adopt parent view's color
253 if (Parent())
254 SetViewColor(Parent()->ViewColor());
258 void
259 ValControl::AllAttached()
261 // move children to requested positions
262 BWindow* pWnd = Window();
263 pWnd->BeginViewTransaction();
265 for_each(fLayoutSet.begin(), fLayoutSet.end(),
266 ptr_fun(&ValCtrlLayoutEntry::InitChildFrame)); // +++++?
268 pWnd->EndViewTransaction();
272 //! Paint decorations (& decimal point)
273 void
274 ValControl::Draw(BRect updateRect)
276 // draw lightweight entries:
277 for (unsigned int n = 0; n < fLayoutSet.size(); n++) {
278 if (fLayoutSet[n].type == ValCtrlLayoutEntry::DECIMAL_POINT_ENTRY)
279 drawDecimalPoint(fLayoutSet[n]);
284 void
285 ValControl::drawDecimalPoint(ValCtrlLayoutEntry& e)
287 rgb_color dark = {0, 0, 0, 255};
288 rgb_color med = {200, 200, 200, 255};
289 // rgb_color light = {244,244,244,255};
291 BPoint center;
292 center.x = e.frame.left + 1;
293 center.y = baselineOffset() - 1;
295 SetHighColor(dark);
296 StrokeLine(center, center);
297 SetHighColor(med);
298 StrokeLine(center - BPoint(0, 1), center + BPoint(1, 0));
299 StrokeLine(center - BPoint(1, 0), center + BPoint(0, 1));
301 // SetHighColor(light);
302 // StrokeLine(center+BPoint(-1,1), center+BPoint(-1,1));
303 // StrokeLine(center+BPoint(1,1), center+BPoint(1,1));
304 // StrokeLine(center+BPoint(-1,-1), center+BPoint(-1,-1));
305 // StrokeLine(center+BPoint(1,-1), center+BPoint(1,-1));
309 void
310 ValControl::FrameResized(float width, float height)
312 _Inherited::FrameResized(width,height);
313 if (fHaveBackBuffer)
314 _AllocBackBuffer(width, height);
316 // PRINT((
317 // "# ValControl::FrameResized(): %.1f, %.1f\n",
318 // width, height));
322 void
323 ValControl::GetPreferredSize(float* outWidth, float* outHeight)
325 ASSERT(fLayoutSet.size() > 0);
327 *outWidth =
328 fLayoutSet.back().frame.right -
329 fLayoutSet.front().frame.left;
331 *outHeight = 0;
332 for(layout_set::const_iterator it = fLayoutSet.begin();
333 it != fLayoutSet.end(); ++it) {
334 if((*it).frame.Height() > *outHeight)
335 *outHeight = (*it).frame.Height();
338 // PRINT((
339 // "# ValControl::GetPreferredSize(): %.1f, %.1f\n",
340 // *outWidth, *outHeight));
344 void
345 ValControl::MakeFocus(bool focused)
347 _Inherited::MakeFocus(focused);
349 // +++++ only the underline needs to be redrawn
350 _InvalidateAll();
354 void
355 ValControl::MouseDown(BPoint where)
357 MakeFocus(true);
361 void
362 ValControl::MessageReceived(BMessage* message)
364 status_t err;
365 const char* stringValue;
367 // PRINT((
368 // "ValControl::MessageReceived():\n"));
369 // message->PrintToStream();
371 switch (message->what) {
372 case M_SET_VALUE:
373 err = message->FindString("_value", &stringValue);
374 if(err < B_OK) {
375 PRINT((
376 "! ValControl::MessageReceived(): no _value found!\n"));
377 break;
380 // set from string
381 err = setValueFrom(stringValue);
382 if (err < B_OK) {
383 PRINT((
384 "! ValControl::MessageReceived(): setValueFrom('%s'):\n"
385 " %s\n",
386 stringValue,
387 strerror(err)));
390 // +++++ broadcast new value +++++ [23aug99]
391 break;
393 case M_GET_VALUE: // +++++
394 break;
396 default:
397 _Inherited::MessageReceived(message);
402 // -------------------------------------------------------- //
403 // archiving/instantiation
404 // -------------------------------------------------------- //
406 ValControl::ValControl(BMessage* archive)
407 : BControl(archive),
408 fDirty(true)
410 // fetch parameters
411 archive->FindInt32("updateMode", (int32*)&fUpdateMode);
412 archive->FindInt32("alignMode", (int32*)&fAlignMode);
413 archive->FindInt32("alignFlags", (int32*)&fAlignFlags);
415 // original bounds
416 archive->FindRect("origBounds", &fOrigBounds);
420 status_t
421 ValControl::Archive(BMessage* archive, bool deep) const
423 status_t err = _Inherited::Archive(archive, deep);
425 // write parameters
426 if (err == B_OK)
427 err = archive->AddInt32("updateMode", (int32)fUpdateMode);
428 if (err == B_OK)
429 err = archive->AddInt32("alignMode", (int32)fAlignMode);
430 if (err == B_OK)
431 err = archive->AddInt32("alignFlags", (int32)fAlignFlags);
432 if (err == B_OK)
433 err = archive->AddRect("origBounds", fOrigBounds);
434 if (err < B_OK)
435 return err;
437 // write layout set?
438 if (!deep)
439 return B_OK;
441 // yes; spew it:
442 for (layout_set::const_iterator it = fLayoutSet.begin();
443 it != fLayoutSet.end(); it++) {
445 // archive entry
446 BMessage layoutSet;
447 ASSERT((*it).pView);
448 err = (*it).pView->Archive(&layoutSet, true);
449 ASSERT(err == B_OK);
451 // write it
452 archive->AddMessage("layoutSet", &layoutSet);
455 return B_OK;
459 // -------------------------------------------------------- //
460 // internal operations
461 // -------------------------------------------------------- //
463 // add segment view (which is responsible for generating its
464 // own ValCtrlLayoutEntry)
465 void
466 ValControl::_Add(ValControlSegment* segment, entry_location from,
467 uint16 distance)
469 BWindow* pWnd = Window();
470 if(pWnd)
471 pWnd->BeginViewTransaction();
473 AddChild(segment);
475 segment->SetFont(&fValueFont);
476 segment->fontChanged(&fValueFont);
478 uint16 nIndex = _LocationToIndex(from, distance);
479 ValCtrlLayoutEntry entry = segment->makeLayoutEntry();
480 _InsertEntry(entry, nIndex);
481 // linkSegment(segment, nIndex);
483 if (pWnd)
484 pWnd->EndViewTransaction();
488 // add general view (manipulator, label, etc.)
489 // the entry's frame rectangle will be filled in
490 void
491 ValControl::_Add(ValCtrlLayoutEntry& entry, entry_location from)
493 BWindow* window = Window();
494 if (window)
495 window->BeginViewTransaction();
497 if (entry.pView)
498 AddChild(entry.pView);
500 uint16 index = _LocationToIndex(from, 0);
501 _InsertEntry(entry, index);
503 if (window)
504 window->EndViewTransaction();
508 // access child-view ValCtrlLayoutEntry
509 // (_IndexOf returns index from left)
510 const ValCtrlLayoutEntry&
511 ValControl::_EntryAt(entry_location from, uint16 distance) const
513 uint16 nIndex = _LocationToIndex(from, distance);
514 ASSERT(nIndex < fLayoutSet.size());
515 return fLayoutSet[nIndex];
519 const ValCtrlLayoutEntry&
520 ValControl::_EntryAt(uint16 offset) const
522 uint16 nIndex = _LocationToIndex(FROM_LEFT, offset);
523 ASSERT(nIndex < fLayoutSet.size());
524 return fLayoutSet[nIndex];
528 uint16
529 ValControl::_IndexOf(BView* child) const
531 for (uint16 n = 0; n < fLayoutSet.size(); n++) {
532 if (fLayoutSet[n].pView == child)
533 return n;
536 ASSERT(!"shouldn't be here");
537 return 0;
541 uint16
542 ValControl::CountEntries() const
544 return fLayoutSet.size();
548 // pop up keyboard input field +++++
549 void
550 ValControl::showEditField()
552 BString valueString;
554 #if defined(DEBUG)
555 status_t err = getString(valueString);
556 ASSERT(err == B_OK);
557 #endif // DEBUG
559 BRect f = Bounds().OffsetByCopy(4.0, -4.0);
560 ConvertToScreen(&f);
561 //PRINT((
562 //"# ValControl::showEditField(): base bounds (%.1f, %.1f)-(%.1f,%.1f)\n",
563 //f.left, f.top, f.right, f.bottom));
565 new TextControlFloater(f, B_ALIGN_RIGHT, &fValueFont, valueString.String(),
566 BMessenger(this), new BMessage(M_SET_VALUE));
567 // TextControlFloater embeds new value
568 // in message: _value (string) +++++ DO NOT HARDCODE
572 //! (Re-)initialize backbuffer
573 void
574 ValControl::_AllocBackBuffer(float width, float height)
576 ASSERT(fHaveBackBuffer);
577 if (fBackBuffer && fBackBuffer->Bounds().Width() >= width
578 && fBackBuffer->Bounds().Height() >= height)
579 return;
581 if (fBackBuffer) {
582 delete fBackBuffer;
583 fBackBuffer = NULL;
584 fBackBufferView = NULL;
587 BRect bounds(0, 0, width, height);
588 fBackBuffer = new BBitmap(bounds, B_RGB32, true);
589 fBackBufferView = new BView(bounds, "back", B_FOLLOW_NONE, B_WILL_DRAW);
590 fBackBuffer->AddChild(fBackBufferView);
594 // ref'd view must already be a child +++++
595 // (due to GetPreferredSize implementation in segment views)
596 void
597 ValControl::_InsertEntry(ValCtrlLayoutEntry& entry, uint16 index)
599 // view ptr must be 0, or a ValControlSegment that's already a child
600 ValControlSegment* pSeg = dynamic_cast<ValControlSegment*>(entry.pView);
601 if (entry.pView)
602 ASSERT(pSeg);
603 if (pSeg)
604 ASSERT(this == pSeg->Parent());
606 // entry must be at one side or the other:
607 ASSERT(!index || index == fLayoutSet.size());
609 // figure padding
610 bool bNeedsPadding =
611 !(entry.flags & ValCtrlLayoutEntry::LAYOUT_NO_PADDING ||
612 ((index - 1 >= 0 &&
613 fLayoutSet[index - 1].flags & ValCtrlLayoutEntry::LAYOUT_NO_PADDING)) ||
614 ((index + 1 < static_cast<uint16>(fLayoutSet.size()) &&
615 fLayoutSet[index + 1].flags & ValCtrlLayoutEntry::LAYOUT_NO_PADDING)));
617 entry.fPadding = (bNeedsPadding) ? fSegmentPadding : 0.0;
619 // fetch (and grant) requested frame size
620 BRect frame(0, 0, 0, 0);
621 if (pSeg)
622 pSeg->GetPreferredSize(&frame.right, &frame.bottom);
623 else
624 _GetDefaultEntrySize(entry.type, &frame.right, &frame.bottom);
626 // figure amount this entry will displace:
627 float fDisplacement = frame.Width() + entry.fPadding + 1;
629 // set entry's top-left position:
630 if (!fLayoutSet.size()) {
631 // sole entry:
632 if (fAlignMode == ALIGN_FLUSH_RIGHT)
633 frame.OffsetBy(Bounds().right - frame.Width(), 0.0);
634 } else if (index) {
635 // insert at right side
636 if (fAlignMode == ALIGN_FLUSH_LEFT)
637 frame.OffsetBy(fLayoutSet.back().frame.right + 1 + entry.fPadding, 0.0);
638 else
639 frame.OffsetBy(fLayoutSet.back().frame.right - frame.Width(), 0.0); //+++++
640 } else {
641 // insert at left side
642 if (fAlignMode == ALIGN_FLUSH_RIGHT)
643 frame.OffsetBy(fLayoutSet.front().frame.left - fDisplacement, 0.0);
646 // add to layout set
647 entry.frame = frame;
648 fLayoutSet.insert(
649 index ? fLayoutSet.end() : fLayoutSet.begin(),
650 entry);
652 // slide following or preceding entries (depending on align mode)
653 // to make room:
654 switch (fAlignMode) {
655 case ALIGN_FLUSH_LEFT:
656 // following entries are shifted to the right
657 for(uint32 n = index+1; n < fLayoutSet.size(); n++)
658 _SlideEntry(n, fDisplacement);
659 break;
661 case ALIGN_FLUSH_RIGHT: {
662 // preceding entries are shifted to the left
663 for(int n = index-1; n >= 0; n--)
664 _SlideEntry(n, -fDisplacement);
666 break;
670 // PRINT((
671 // "### added entry: (%.1f,%.1f)-(%.1f,%.1f)\n",
672 // frame.left, frame.top, frame.right, frame.bottom));
676 void
677 ValControl::_SlideEntry(int index, float delta)
679 ValCtrlLayoutEntry& e = fLayoutSet[index];
680 e.frame.OffsetBy(delta, 0.0);
682 // move & possibly resize view:
683 if (e.pView) {
684 e.pView->MoveTo(e.frame.LeftTop());
686 BRect curFrame = e.pView->Frame();
687 float fWidth = e.frame.Width();
688 float fHeight = e.frame.Height();
689 if (curFrame.Width() != fWidth
690 || curFrame.Height() != fHeight)
691 e.pView->ResizeTo(fWidth + 5.0, fHeight);
696 uint16
697 ValControl::_LocationToIndex(entry_location from, uint16 distance) const
699 uint16 nResult = 0;
701 switch (from) {
702 case FROM_LEFT:
703 nResult = distance;
704 break;
706 case FROM_RIGHT:
707 nResult = fLayoutSet.size() - distance;
708 break;
711 ASSERT(nResult <= fLayoutSet.size());
712 return nResult;
716 void
717 ValControl::_GetDefaultEntrySize(ValCtrlLayoutEntry::entry_type type,
718 float* outWidth, float* outHeight)
720 switch (type) {
721 case ValCtrlLayoutEntry::SEGMENT_ENTRY:
722 case ValCtrlLayoutEntry::VIEW_ENTRY:
723 *outWidth = 1.0;
724 *outHeight = 1.0;
725 break;
727 case ValCtrlLayoutEntry::DECIMAL_POINT_ENTRY:
728 *outWidth = fDecimalPointWidth;
729 *outHeight = fDecimalPointHeight;
730 break;