PrevNextUpHome SophiaFramework UNIVERSE 5.3

9.19. Control(Applied)

In this section, several methods to use more than one control at a time or synchronize multiple controls will be described.

9.19.1. Changing the Border Color in the Focused State

Figure 9.75. Execution Result

Execution Result

In a control such as SFZTextButtonControl or SFZImageButtonControl, the color in which the border of the control responder in the focus state is drawn can be changed.

This function is used to emphasize that the control responder is in the focus state or change the color set of user interface.

Example 9.137. Declaration

SFMTYPEDEFRESPONDER(USRWindow)
class USRWindow: public SFZWindow {
    SFMSEALRESPONDER(USRWindow)
    SFMRESPONDERINSTANTIATEFOUR(USRWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)
private:
    SFZTextButtonControlSmp _button;

    ...
private:
    SFCError Make(Void);
};

Example 9.138. Implementation

SFCError USRWindow::Make(Void)
{
    SFCError error(SFERR_NO_ERROR);

    if ((_button = SFZTextButtonControl::NewInstance(&error)) != null) {

        error = _button->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {

            error = _button->SetText("hello world");
            if (error == SFERR_NO_ERROR) {

                // get default focus border's color, add red element of RGB color on it and set it
                _button->SetFocusColor(SFXBevelColor(_button->GetFocusColor()).AddRed(0xFF));

                _button->SetRealBound(_button->GetSuitableBound().SetOrigin(10, 10));
                _button->SetState(true, true, true, true);
            }
        }
    }

    return error;
}

9.19.2. Changing the Color of a Control

Figure 9.76. Execution Result

Execution Result

In a control such as SFZTextButtonControl or SFZImageButtonControl, the colors of various parts other than the focus border can be changed.

The parts whose colors can be changed depend on the type of control or its implementation.

Example 9.139. Declaration

SFMTYPEDEFRESPONDER(USRWindow)
class USRWindow: public SFZWindow {
    SFMSEALRESPONDER(USRWindow)
    SFMRESPONDERINSTANTIATEFOUR(USRWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)
private:
    SFZTextButtonControlSmp _button;

    ...
private:
    SFCError Make(Void);
};

Example 9.140. Implementation

SFCError USRWindow::Make(Void)
{
    SFCError error(SFERR_NO_ERROR);

    if ((_button = SFZTextButtonControl::NewInstance(&error)) != null) {

        error = _button->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {

            error = _button->SetText("hello world");
            if (error == SFERR_NO_ERROR) {

                // get default focus border's color, subtract red and green elements of RGB color from it and set
                _button->SetFocusColor(SFXBevelColor(_button->GetFocusColor()).SubRGB(0x33, 0x33, 0x00));

                // get default button color, subtract red and green elements of RGB color from it and set
                _button->SetButtonColor(SFXBevelColor(_button->GetButtonColor()).SubRGB(0x33, 0x33, 0x00));

                _button->SetRealBound(_button->GetSuitableBound().SetOrigin(10, 10));
                _button->SetState(true, true, true, true);
            }
        }
    }

    return error;
}

9.19.3. Getting the Suitable Size of Responder for Displaying a Multiple Text

Figure 9.77. Execution Result

Execution Result

In a responder to display a multiple text such as SFZMultipleTextLabelControl or SFZMultipleTextBoxControl, the SFYResponder::GetSuitableBound function with no rectangle argument will behave differently from other responders.

This kind of responder needs the hint value to calculate the suitable region for displaying a multiple text.

Concretely, if no rectangular region is specified in the argument of SFYResponder::GetSuitableBound of the responder, the width of the real region set with the SFYResponder::SetRealBound function is used as a hint value.

[Note] Note
The value greater than the width of the current font will be set for the width of real region(hint value).

This hint value is used as below.

  1. A multiple text is splitted into more than one string separated with the "\n" character(carriage return).
  2. If the length of a string exceeds the hint value, the string will be turned down by the width of this hint value.
  3. If there is no need to turn down any string, the maximum width among the separated strings will be the width of the calculated region. On the other hand, if it is necessary to turn down some strings, the maximum value of integral multiples of one character width less than the hint value will be the width of the calculated suitable region.
  4. The height of rows of the multiple text after turning down all strings with the hint value will be that of the calculated suitable region.

In case of specifying the rectangle argument of SFYResponder::GetSuitableBound, there is no need to set the real region as a hint value just before calculating the suitable region.

Table 9.30.  Responders which need the width of real region to be set just before calling GetSuitableBound() with no argument

Class name Description
SFYMultipleTextWidget Widget to display a multiple uneditable text.
SFYMultipleEditWidget Widget to display a multiple editable text.
SFZMultipleTextLabelControl Label control to display a multiple uneditable text.
SFZMultipleEditLabelControl Label control to display a multiple editable text.
SFZMultipleTextBoxControl Box control to display a multiple uneditable text.
SFZMultipleEditBoxControl Box control to display a multiple editable text.
SFZMessageDialog Dialog to display a notification message.
SFZQuestionDialog Dialog to display a selection message.

Example 9.141. Declaration

SFMTYPEDEFRESPONDER(USRWindow)
class USRWindow: public SFZWindow {
    SFMSEALRESPONDER(USRWindow)
    SFMRESPONDERINSTANTIATEFOUR(USRWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)
private:
    SFZMultipleTextLabelControlSmp _label;

    ...
private:
    SFCError Make(Void);
};

Example 9.142. Implementation

SFCError USRWindow::Make(Void)
{
    SFCError error(SFERR_NO_ERROR);

    if ((_label = SFZMultipleTextLabelControl::NewInstance(&error)) != null) {

        error = _label->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {

            error = _label->SetText("hello world\n\n"
                                    "0          \n"
                                    " 1         \n"
                                    "  2        \n"
                                    "   3       \n"
                                    "    4      \n"
                                    "     5     \n"
                                    "      6    \n"
                                    "       7   \n"
                                    "        8  \n"
                                    "         9 \n"
                                    "          0");
            if (error == SFERR_NO_ERROR) {

                // set hint value
                _label->SetRealBound(GetLocalBound().Deflate(10, 10));

                // get suitable size without specifying rectangle and set it
                _label->SetRealBound(_label->GetSuitableBound().SetOrigin(10, 10));

                _label->SetState(true, true, true, true);
            }
        }
    }

    return error;
}

Reference: Real Region | Local Region | Virtual Region

9.19.4. Placing More Than One Control inside a Container

Figure 9.78. Execution Result

Execution Result

When more than one control in a container are placed, the SFYResponder::GetSuitableBound function can be used to realize user interface with high usability.

Example 9.143. Declaration

SFMTYPEDEFRESPONDER(USRWindow)
class USRWindow: public SFZWindow {
    SFMSEALRESPONDER(USRWindow)
    SFMRESPONDERINSTANTIATEFOUR(USRWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)
private:
    SFZTextButtonControlSmp _button;
    SFZSingleTextBoxControlSmp _box;
    SFZCheckboxControlSmp _checkbox;

    ...
private:
    SFCError Make(Void);
};

Example 9.144. Implementation

SFCError USRWindow::Make(Void)
{
    SFXRectangle rectangle;
    SFCError error(SFERR_NO_ERROR);

    // set left-top coordinate of 1st control
    rectangle.Set(GetLocalBound().Deflate(10, 10));

    // make 1st control
    if ((_button = SFZTextButtonControl::NewInstance(&error)) != null) {

        error = _button->SetParent(GetThis());
        if (error == SFERR_NO_ERROR) {

            error = _button->SetText("first");
            if (error == SFERR_NO_ERROR) {

                _button->SetRealBound(_button->GetSuitableBound(rectangle));
                _button->SetState(true, true, true, true);

                // calculate left-top coordinate of 2nd control
                rectangle.AddY(_button->GetRealBound().GetHeight() + 5);

                // make 2nd control
                if ((_box = SFZSingleTextBoxControl::NewInstance(&error)) != null) {

                    error = _box->SetParent(GetThis());
                    if (error == SFERR_NO_ERROR) {

                        error = _box->SetText("second");
                        if (error == SFERR_NO_ERROR) {

                            _box->SetRealBound(_box->GetSuitableBound(rectangle));
                            _box->SetState(true, true, true, false);

                            // calculate left-top coordinate of 3rd control
                            rectangle.AddY(_box->GetRealBound().GetHeight() + 5);

                            // make 3rd control
                            if ((_checkbox = SFZCheckboxControl::NewInstance(&error)) != null) {

                                error = _checkbox->SetParent(GetThis());
                                if (error == SFERR_NO_ERROR) {

                                    error = _checkbox->SetText("third");
                                    if (error == SFERR_NO_ERROR) {

                                        _checkbox->SetRealBound(_checkbox->GetSuitableBound(rectangle));
                                        _checkbox->SetState(true, true, true, false);

                                        // calculate left-top coordinate of 4th control
                                        rectangle.AddY(_checkbox->GetRealBound().GetHeight() + 5);
                                        ...
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    return error;
}

9.19.5. Grouping More Than One Radio Button Control

Figure 9.79. Execution Result

Execution Result

In the code below, exclusive switching of the checked state will be automatically implemented by grouping multiple radio button controls.

[Note] Note
Automatic exclusive switching can be realized only through the key operation. If the checked state is set with the SFYControl::SetCurrentValue function, exclusive switching will not be realized.

Example 9.145. Declaration

SFMTYPEDEFRESPONDER(USRWindow)
class USRWindow: public SFZWindow {
    SFMSEALRESPONDER(USRWindow)
    SFMRESPONDERINSTANTIATEFOUR(USRWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)
private:
    SFZRadiobuttonControlSmp _radiobutton[5];

    ...
private:
    SFCError Make(Void);
};

Example 9.146. Implementation

SFCError USRWindow::Make(Void)
{
    SFXRectangle rectangle;
    SInt16 i;
    SFCError error(SFERR_NO_ERROR);

    rectangle.Set(GetLocalBound().Deflate(10, 10));

    // make radio button controls
    for (i = 0; i < 5 & error == SFERR_NO_ERROR; ++i) {

        if ((_radiobutton[i] = SFZRadiobuttonControl::NewInstance(&error)) != null) {

            error = _radiobutton[i]->SetParent(GetThis());
            if (error == SFERR_NO_ERROR) {

                error = _radiobutton[i]->SetText(SFXWideString::Format("number %d", i));
                if (error == SFERR_NO_ERROR) {

                    _radiobutton[i]->SetRealBound(_radiobutton[i]->GetSuitableBound(rectangle));
                    _radiobutton[i]->SetState(true, true, true, false);
                    rectangle.AddY(_radiobutton[i]->GetRealBound().GetHeight() + 5);
                }
            }
        }
    }
    if (error == SFERR_NO_ERROR) {

        // group all radio button controls
        for (i = 1; i < 5; ++i) {

            _radiobutton[i]-> group(_radiobutton[0]);
        }

        // set checked state of 1st radio button control to "true"
        _radiobutton[0]->SetCurrentValue(true);

        // move focus to 1st radio button control
        _radiobutton[0]->SetStateFocus(true);
    }

    return error;
}

9.19.6. Switching the Active State of Check Box Control according to its State

Figure 9.80. Execution Result

Execution Result

In the code below, user interface with high usability is realized by switching the active state of related controls depending on the state of the corresponding check box control.

Example 9.147. Declaration

SFMTYPEDEFRESPONDER(USRWindow)
class USRWindow: public SFZWindow {
    SFMSEALRESPONDER(USRWindow)
    SFMRESPONDERINSTANTIATEFOUR(USRWindow, SFZWindow, SFYContainer, SFYWidget, SFYResponder)
private:
    SFZCheckboxControlSmp _checkbox[2];
    SFZRadiobuttonControlSmp _radiobutton[3];
    SFZSingleEditBoxControlSmp _editbox;

    ...
private:
    SFCError Make(Void);
    SFCError Init(SFYResponderSmpConstRef responder, SFXRectanglePtr rectangle);

    // 1st check box control's handler for check-changed event(value event)
    XANDLER_DECLARE_VOIDVALUE(OnValue0)

    // 2nd check box control's handler for check-changed event(value event)
    XANDLER_DECLARE_VOIDVALUE(OnValue1)
};

Example 9.148. Implementation

SFCError USRWindow::Make(Void)
{
    static ACharConst item[][8] = {
        "Unix", "Mac", "Windows"
    };
    SFXRectangle rectangle;
    SInt16 i;
    SFCError error(SFERR_NO_ERROR);

    rectangle.Set(GetLocalBound().Deflate(10, 10));
    if ((_checkbox[0] = SFZCheckboxControl::NewInstance(&error)) != null) {

        // register check box control's handler for check-changed event(value event)
        error = _checkbox[0]->RegisterHandler(
            SFXEventRange(SFEVT_RESPONDER_VALUE, SFEVT_RESPONDER_VALUE, SFP16_VALUE_CURRENT, SFP16_VALUE_CURRENT),
            XANDLER_INTERNAL(OnValue0)
        );
        if (error == SFERR_NO_ERROR) {

            error = _checkbox[0]->SetText("Use linebreak");
            if (error == SFERR_NO_ERROR) {

                error = Init(_checkbox[0], &rectangle);
                if (error == SFERR_NO_ERROR) {

                    rectangle.AddLeft(10);
                    for (i = 0; i < 3 & error == SFERR_NO_ERROR; ++i) {

                        if ((_radiobutton[i] = SFZRadiobuttonControl::NewInstance(&error)) != null) {

                            error = _radiobutton[i]->SetText(item[i]);
                            if (error == SFERR_NO_ERROR) {

                                error = Init(_radiobutton[i], &rectangle);
                            }
                        }
                    }
                    for (i = 1; i < 3 & error == SFERR_NO_ERROR; ++i) {

                        _radiobutton[i]-> group(_radiobutton[0]);
                    }
                    rectangle.SubLeft(10);
                }
            }
        }
    }
    if (error == SFERR_NO_ERROR) {

        if ((_checkbox[1] = SFZCheckboxControl::NewInstance(&error)) != null) {

            // register check box control's handler for check-changed event(value event)
            error = _checkbox[1]->RegisterHandler(
                SFXEventRange(SFEVT_RESPONDER_VALUE, SFEVT_RESPONDER_VALUE, SFP16_VALUE_CURRENT, SFP16_VALUE_CURRENT),
                XANDLER_INTERNAL(OnValue1)
            );
            if (error == SFERR_NO_ERROR) {

                error = _checkbox[1]->SetText("Use suffix");
                if (error == SFERR_NO_ERROR) {

                    error = Init(_checkbox[1], &rectangle);
                    if (error == SFERR_NO_ERROR) {

                        rectangle.AddLeft(10);
                        if ((_editbox = SFZSingleEditBoxControl::NewInstance(&error)) != null) {

                            error = _editbox->SetText(".txt");
                            if (error == SFERR_NO_ERROR) {

                                error = Init(_editbox, &rectangle);
                            }
                        }
                        rectangle.SubLeft(10);
                    }
                }
            }
        }
    }
    if (error == SFERR_NO_ERROR) {

        // set initial state
        _checkbox[0]->SetCurrentValue(true);
        _radiobutton[0]->SetCurrentValue(true);
        _checkbox[1]->SetCurrentValue(true);
        _checkbox[0]->SetStateFocus(true);
    }

    return error;
}

SFCError USRWindow::Init(SFYResponderSmpConstRef responder, SFXRectanglePtr rectangle)
{
    SFCError error(SFERR_NO_ERROR);

    error = responder->SetParent(GetThis());
    if (error == SFERR_NO_ERROR) {

        responder->SetRealBound(responder->GetSuitableBound(*rectangle));
        responder->SetState(true, true, true, false);
        rectangle->AddY(responder->GetRealBound().GetHeight() + 5);
    }

    return error;
}

XANDLER_IMPLEMENT_VOIDVALUE(USRWindow, OnValue0, invoker, reason, value)
{
    SInt16 i;

    // according to check box control's state,
    // switch active state
    for (i = 0; i < 3; ++i) {

        _radiobutton[i]->SetStateActive(value != 0);
    }

    return;
}

XANDLER_IMPLEMENT_VOIDVALUE(USRWindow, OnValue1, invoker, reason, value)
{
    // according to check box control's state,
    // switch active state
    _editbox->SetStateActive(value != 0);

    return;
}