root/src/apps/pulse/ConfigView.cpp
/*
 * Copyright 2002-2009, Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT license.
 *
 * Copyright 1999, Be Incorporated. All Rights Reserved.
 * This file may be used under the terms of the Be Sample Code License.
 *
 * Written by:  Daniel Switkin
 */


#include "ConfigView.h"
#include "Common.h"
#include "PulseApp.h"
#include "PrefsWindow.h"

#include <Catalog.h>
#include <CheckBox.h>
#include <RadioButton.h>
#include <TextControl.h>

#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "ConfigView"


RTColorControl::RTColorControl(BPoint point, BMessage *message)
        : BColorControl(point, B_CELLS_32x8, 6, "ColorControl", message, false)
{
}


/*!
        Send a message every time the color changes, not just
        when the mouse button is released
*/
void
RTColorControl::SetValue(int32 color)
{
        BColorControl::SetValue(color);
        Invoke();
}


//      #pragma mark -


/*!
        A single class for all three prefs views, needs to be
        customized below to give each control the right message
*/
ConfigView::ConfigView(BRect rect, const char *name, uint32 mode, BMessenger& target,
                Prefs *prefs)
        : BBox(rect, name, B_FOLLOW_NONE, B_WILL_DRAW),
        fMode(mode),
        fTarget(target),
        fPrefs(prefs),
        fFirstTimeAttached(true)
{
        fFadeCheckBox = NULL;
        fActiveButton = fIdleButton = fFrameButton = NULL;
        fIconWidthControl = NULL;

        SetLabel(B_TRANSLATE("Bar colors"));

        font_height fontHeight;
        be_bold_font->GetHeight(&fontHeight);

        fColorControl = new RTColorControl(BPoint(10, 5.0f + fontHeight.ascent
                + fontHeight.descent), new BMessage(fMode));
        fColorControl->ResizeToPreferred();
        AddChild(fColorControl);

        rect = fColorControl->Frame();
        rect.top = rect.bottom + 10.0f;
        rect.bottom = rect.top + 15.0f;

        if (mode == PRV_NORMAL_CHANGE_COLOR) {
                // normal mode

                fFadeCheckBox = new BCheckBox(rect, "FadeColors",
                        B_TRANSLATE("Fade colors"), new BMessage(PRV_NORMAL_FADE_COLORS));
                fFadeCheckBox->ResizeToPreferred();
                AddChild(fFadeCheckBox);

                fColorControl->SetValue(fPrefs->normal_bar_color);
                fFadeCheckBox->SetValue(fPrefs->normal_fade_colors);
        } else if (mode == PRV_MINI_CHANGE_COLOR) {
                // mini mode

                fActiveButton = new BRadioButton(rect, "ActiveColor",
                        B_TRANSLATE("Active color"), new BMessage(PRV_MINI_ACTIVE));
                fActiveButton->ResizeToPreferred();
                fActiveButton->SetValue(B_CONTROL_ON);
                AddChild(fActiveButton);

                rect.left = fActiveButton->Frame().right + 5.0f;
                fIdleButton = new BRadioButton(rect, "IdleColor",
                        B_TRANSLATE("Idle color"), new BMessage(PRV_MINI_IDLE));
                fIdleButton->ResizeToPreferred();
                AddChild(fIdleButton);

                rect.left = fIdleButton->Frame().right + 5.0f;
                fFrameButton = new BRadioButton(rect, "FrameColor",
                        B_TRANSLATE("Frame color"),     new BMessage(PRV_MINI_FRAME));
                fFrameButton->ResizeToPreferred();
                AddChild(fFrameButton);

                fColorControl->SetValue(fPrefs->mini_active_color);
        } else {
                // deskbar mode
                fActiveButton = new BRadioButton(rect, "ActiveColor",
                        B_TRANSLATE("Active color"), new BMessage(PRV_DESKBAR_ACTIVE));
                fActiveButton->ResizeToPreferred();
                fActiveButton->SetValue(B_CONTROL_ON);
                AddChild(fActiveButton);

                rect.left = fActiveButton->Frame().right + 5.0f;
                fIdleButton = new BRadioButton(rect, "IdleColor",
                        B_TRANSLATE("Idle color"), new BMessage(PRV_DESKBAR_IDLE));
                fIdleButton->ResizeToPreferred();
                AddChild(fIdleButton);

                rect.left = fIdleButton->Frame().right + 5.0f;
                fFrameButton = new BRadioButton(rect, "FrameColor",
                        B_TRANSLATE("Frame color"),     new BMessage(PRV_DESKBAR_FRAME));
                fFrameButton->ResizeToPreferred();
                AddChild(fFrameButton);

                rect.left = fColorControl->Frame().left;
                rect.top = fActiveButton->Frame().bottom + 5.0f;

                char temp[10];
                snprintf(temp, sizeof(temp), "%d", fPrefs->deskbar_icon_width);
                fIconWidthControl = new BTextControl(rect, "Width",
                        B_TRANSLATE("Width of icon:"), temp,
                        new BMessage(PRV_DESKBAR_ICON_WIDTH));
                AddChild(fIconWidthControl);
                fIconWidthControl->SetDivider(be_plain_font->StringWidth(
                        fIconWidthControl->Label()) + 5.0f);

                for (int c = 0; c < 256; c++) {
                        if (!isdigit(c))
                                fIconWidthControl->TextView()->DisallowChar(c);
                }
                fIconWidthControl->TextView()->SetMaxBytes(2);

                float width, height;
                fIconWidthControl->GetPreferredSize(&width, &height);
                fIconWidthControl->ResizeTo(fIconWidthControl->Divider() + 32.0f
                        + fIconWidthControl->StringWidth("999"), height);

                fColorControl->SetValue(fPrefs->deskbar_active_color);
        }
}


void
ConfigView::GetPreferredSize(float* _width, float* _height)
{
        float right, bottom;

        if (fMode == PRV_NORMAL_CHANGE_COLOR) {
                // normal mode
                bottom = fFadeCheckBox->Frame().bottom;
                right = fFadeCheckBox->Frame().right;
        } else if (fMode == PRV_MINI_CHANGE_COLOR) {
                // mini mode
                bottom = fIdleButton->Frame().bottom;
                right = fFrameButton->Frame().right;
        } else {
                // deskbar mode
                bottom = fIconWidthControl->Frame().bottom;
                right = fFrameButton->Frame().right;
        }

        if (right < fColorControl->Frame().right)
                right = fColorControl->Frame().right;
        if (right < 300)
                right = 300;

        if (_width)
                *_width = right + 10.0f;
        if (_height)
                *_height = bottom + 8.0f;
}


void
ConfigView::AttachedToWindow()
{
        BView::AttachedToWindow();

        // AttachedToWindow() gets called every time this tab is brought
        // to the front, but we only want this initialization to happen once
        if (fFirstTimeAttached) {
                AdoptParentColors();

                if (Parent() == NULL)
                        SetViewUIColor(B_PANEL_BACKGROUND_COLOR);

                BMessenger messenger(this);
                fColorControl->SetTarget(messenger);
                if (fFadeCheckBox != NULL)
                        fFadeCheckBox->SetTarget(messenger);
                if (fActiveButton != NULL)
                        fActiveButton->SetTarget(messenger);
                if (fIdleButton != NULL)
                        fIdleButton->SetTarget(messenger);
                if (fFrameButton != NULL)
                        fFrameButton->SetTarget(messenger);
                if (fIconWidthControl != NULL)
                        fIconWidthControl->SetTarget(messenger);

                fFirstTimeAttached = false;
        }
}


void
ConfigView::MessageReceived(BMessage *message)
{
        switch (message->what) {
                // These two send the color and the status of the fade checkbox together
                case PRV_NORMAL_FADE_COLORS:
                case PRV_NORMAL_CHANGE_COLOR:
                {
                        bool fade_colors = (bool)fFadeCheckBox->Value();
                        int32 bar_color = fColorControl->Value();
                        message->AddInt32("color", bar_color);
                        message->AddBool("fade", fade_colors);
                        fPrefs->normal_fade_colors = fade_colors;
                        fPrefs->normal_bar_color = bar_color;

                        fTarget.SendMessage(message);
                        break;
                }
                // Share the single color control among three values
                case PRV_MINI_ACTIVE:
                        fColorControl->SetValue(fPrefs->mini_active_color);
                        break;
                case PRV_MINI_IDLE:
                        fColorControl->SetValue(fPrefs->mini_idle_color);
                        break;
                case PRV_MINI_FRAME:
                        fColorControl->SetValue(fPrefs->mini_frame_color);
                        break;
                case PRV_MINI_CHANGE_COLOR: {
                        int32 color = fColorControl->Value();
                        if (fActiveButton->Value())
                                fPrefs->mini_active_color = color;
                        else if (fIdleButton->Value())
                                fPrefs->mini_idle_color = color;
                        else
                                fPrefs->mini_frame_color = color;

                        message->AddInt32("active_color", fPrefs->mini_active_color);
                        message->AddInt32("idle_color", fPrefs->mini_idle_color);
                        message->AddInt32("frame_color", fPrefs->mini_frame_color);
                        fTarget.SendMessage(message);
                        break;
                }
                case PRV_DESKBAR_ACTIVE:
                        fColorControl->SetValue(fPrefs->deskbar_active_color);
                        break;
                case PRV_DESKBAR_IDLE:
                        fColorControl->SetValue(fPrefs->deskbar_idle_color);
                        break;
                case PRV_DESKBAR_FRAME:
                        fColorControl->SetValue(fPrefs->deskbar_frame_color);
                        break;
                case PRV_DESKBAR_ICON_WIDTH:
                        UpdateDeskbarIconWidth();
                        break;
                case PRV_DESKBAR_CHANGE_COLOR: {
                        int32 color = fColorControl->Value();
                        if (fActiveButton->Value())
                                fPrefs->deskbar_active_color = color;
                        else if (fIdleButton->Value())
                                fPrefs->deskbar_idle_color = color;
                        else
                                fPrefs->deskbar_frame_color = color;

                        message->AddInt32("active_color", fPrefs->deskbar_active_color);
                        message->AddInt32("idle_color", fPrefs->deskbar_idle_color);
                        message->AddInt32("frame_color", fPrefs->deskbar_frame_color);
                        fTarget.SendMessage(message);
                        break;
                }
                case PRV_BOTTOM_DEFAULTS:
                        _ResetDefaults();
                        break;
                default:
                        BView::MessageReceived(message);
                        break;
        }
}


void
ConfigView::UpdateDeskbarIconWidth()
{
        // Make sure the width shows at least one pixel per CPU and
        // that it will fit in the tray in any Deskbar orientation
        int width = atoi(fIconWidthControl->Text());
        int min_width = GetMinimumViewWidth();
        if (width < min_width || width > 50) {
                char temp[12];
                if (width < min_width) {
                        snprintf(temp, 12, "%d", min_width);
                        width = min_width;
                } else {
                        strcpy(temp, "50");
                        width = 50;
                }
                fIconWidthControl->SetText(temp);
        }

        fPrefs->deskbar_icon_width = width;

        BMessage message(PRV_DESKBAR_ICON_WIDTH);
        message.AddInt32("width", width);
        fTarget.SendMessage(&message);
}


void
ConfigView::_ResetDefaults()
{
        if (fMode == PRV_NORMAL_CHANGE_COLOR) {
                fColorControl->SetValue(DEFAULT_NORMAL_BAR_COLOR);
                fFadeCheckBox->SetValue(DEFAULT_NORMAL_FADE_COLORS);
        } else if (fMode == PRV_MINI_CHANGE_COLOR) {
                fPrefs->mini_active_color = DEFAULT_MINI_ACTIVE_COLOR;
                fPrefs->mini_idle_color = DEFAULT_MINI_IDLE_COLOR;
                fPrefs->mini_frame_color = DEFAULT_MINI_FRAME_COLOR;
                if (fActiveButton->Value())
                        fColorControl->SetValue(DEFAULT_MINI_ACTIVE_COLOR);
                else if (fIdleButton->Value())
                        fColorControl->SetValue(DEFAULT_MINI_IDLE_COLOR);
                else
                        fColorControl->SetValue(DEFAULT_MINI_FRAME_COLOR);

                BMessage *message = new BMessage(PRV_MINI_CHANGE_COLOR);
                message->AddInt32("active_color", DEFAULT_MINI_ACTIVE_COLOR);
                message->AddInt32("idle_color", DEFAULT_MINI_IDLE_COLOR);
                message->AddInt32("frame_color", DEFAULT_MINI_FRAME_COLOR);
                fTarget.SendMessage(message);
        } else {
                fPrefs->deskbar_active_color = DEFAULT_DESKBAR_ACTIVE_COLOR;
                fPrefs->deskbar_idle_color = DEFAULT_DESKBAR_IDLE_COLOR;
                fPrefs->deskbar_frame_color = DEFAULT_DESKBAR_FRAME_COLOR;
                if (fActiveButton->Value())
                        fColorControl->SetValue(DEFAULT_DESKBAR_ACTIVE_COLOR);
                else if (fIdleButton->Value())
                        fColorControl->SetValue(DEFAULT_DESKBAR_IDLE_COLOR);
                else
                        fColorControl->SetValue(DEFAULT_DESKBAR_FRAME_COLOR);

                BMessage *message = new BMessage(PRV_DESKBAR_CHANGE_COLOR);
                message->AddInt32("active_color", DEFAULT_DESKBAR_ACTIVE_COLOR);
                message->AddInt32("idle_color", DEFAULT_DESKBAR_IDLE_COLOR);
                message->AddInt32("frame_color", DEFAULT_DESKBAR_FRAME_COLOR);
                fTarget.SendMessage(message);

                char temp[10];
                snprintf(temp, 10, "%d", DEFAULT_DESKBAR_ICON_WIDTH);
                fIconWidthControl->SetText(temp);
                // Need to force the model message to be sent
                fIconWidthControl->Invoke();
        }
}