Open Search
    GeUserArea Manual

    About

    GeUserArea is the base class for all gadgets that can be displayed in a GeDialog. A new gadget is created by implementing a subclass of GeUserArea. Such a gadget manages user interaction and draws the gadget interface in the GUI.

    Note
    GeUserArea based classes can only be used with a GeDialog or GeDialog based classes. To create a custom GUI element that can be used in the Attribute Manager one must implement a CustomGuiData / iCustomGui based plugin.

    Allocation

    An instance of a GeUserArea based class is typically stored as a member of the parent GeDialog. It is added to the dialog layout using:

    • GeDialog::AddUserArea(): Adds a user area to the dialog layout.
    • GeDialog::AttachUserArea(): Connects the user area gadget with the actual user area instance.

    See GeDialog Manual.

    // This example adds the given user area "userarea" to the GeDialog layout.
    private:
    MyUserArea _geUserArea;
    public:
    Bool CreateLayout()
    {
    SetTitle("GeUserArea Dialog"_s);
    C4DGadget* const userAreaGadget = this->AddUserArea(100, BFH_LEFT, 400, 100);
    if (userAreaGadget)
    this->AttachUserArea(_geUserArea, userAreaGadget);
    maxon::Bool Bool
    Definition: ge_sys_math.h:46
    @ BFH_LEFT
    Aligned to the left. 1<<3.
    Definition: gui.h:312

    The parent dialog is accessible with:

    • GeUserArea::GetDialog(): Returns the parent GeDialog.

    GeUserArea Based Classes

    A custom user area is created by implementing a subclass of GeUserArea. This subclass can implement different virtual functions that define the behaviour of the gadget.

    The user area is initiated with:

    • GeUserArea::Init(): Called once when the user area is initialized.
    • GeUserArea::InitValues(): Initiates the values displayed with the user area.
    // This example initializes the GeUserArea and sets the timer.
    Bool Init()
    {
    this->SetTimer(500); // value in ms
    return true;
    }

    The size of the user area is handled with:

    • GeUserArea::GetMinSize(): Defines the minimum size of the user area.
    • GeUserArea::Sized(): Called when the user area is resized.
    // This example defines the minimum size of this GeUserArea.
    Bool GetMinSize(Int32& w, Int32& h)
    {
    w = 400;
    h = 100;
    return true;
    }
    // This example stores the width and height after the GeUserArea was resized.
    void Sized(Int32 w, Int32 h)
    {
    _width = w;
    _height = h;
    }
    maxon::Int32 Int32
    Definition: ge_sys_math.h:51

    Different messages are sent to a user area:

    // This example catches a message to set the cursor when the mouse is over the user area.
    Int32 Message(const BaseContainer& msg, BaseContainer& result)
    {
    // messages are identified by the BaseContainer ID
    switch (msg.GetId())
    {
    {
    result.SetString(RESULT_BUBBLEHELP, "This is an example GeUserArea"_s);
    return true;
    }
    }
    return GeUserArea::Message(msg, result);
    }
    PyObject PyObject * result
    Definition: abstract.h:43
    @ BFM_GETCURSORINFO
    Definition: gui.h:561
    @ RESULT_BUBBLEHELP
    String Bubble help text.
    Definition: gui.h:565
    @ RESULT_CURSOR
    Int32 Mouse cursor: MOUSE
    Definition: gui.h:564
    static const Int32 MOUSE_POINT_HAND
    Point hand cursor.
    Definition: ge_prepass.h:2733
    const char const char * msg
    Definition: object.h:438

    The primary purpose of a user area is to draw the actual user interface:

    • GeUserArea::DrawMsg(): Called to draw the user area.
    // This example draws a white rectangle in the given region.
    void DrawMsg(Int32 x1, Int32 y1, Int32 x2, Int32 y2, const BaseContainer& msg)
    {
    OffScreenOn();
    SetClippingRegion(x1, y1, x2, y2);
    DrawSetPen(Vector(1, 1, 1));
    DrawRectangle(x1, y1, x2, y2);
    }
    maxon::Vec3< maxon::Float64, 1 > Vector
    Definition: ge_math.h:140
    Note
    To optimize the drawing call skip the redraw if only the focus has changed, see ::BFM_DRAW_REASON in Draw.

    A user area can catch user interaction events:

    • GeUserArea::InputEvent(): Called when an input event (keyboard, mouse) is received.
    // This example checks if the input device is the mouse.
    // If so, the mouse coordinates are transferred into local coordinates.
    Bool InputEvent(const BaseContainer& msg)
    {
    // check the input device
    switch (msg.GetInt32(BFM_INPUT_DEVICE))
    {
    // some mouse interaction
    {
    // get the cursor position
    Int32 mx = msg.GetInt32(BFM_INPUT_X);
    Int32 my = msg.GetInt32(BFM_INPUT_Y);
    Global2Local(&mx, &my);
    ApplicationOutput("Mouse Event at " + String::IntToString(mx) + " - " + String::IntToString(my));
    return true;
    }
    }
    return false;
    }
    @ BFM_INPUT_MOUSE
    Mouse.
    Definition: gui.h:711
    @ BFM_INPUT_Y
    Float Y value.
    Definition: gui.h:729
    @ BFM_INPUT_DEVICE
    Int32 Device:
    Definition: gui.h:710
    @ BFM_INPUT_X
    Float X value.
    Definition: gui.h:728
    #define ApplicationOutput(formatString,...)
    Definition: debugdiagnostics.h:204

    See also GeDialog Gadget Interaction.

    Read-Only Properties

    These properties can be read from a user area:

    • GeUserArea::GetId(): Returns the ID of the user area.
    • GeUserArea::GetWidth(): Returns the width of the user area.
    • GeUserArea::GetHeight(): Returns the height of the user area.
    • GeUserArea::IsEnabled(): Returns true if the user area is enabled.
    • GeUserArea::IsR2L(): Returns true if the user area should be drawn in right-to-left layout mode (Arabic interface).
    • GeUserArea::HasFocus(): Returns true if the user area has the focus.
    // This example sends the BFM_ACTION message from a GeUserArea to the parent GUI element.
    // This message can be caught in GeDialog::Message() or GeDialog::Command().
    BaseContainer action(BFM_ACTION);
    action.SetInt32(BFM_ACTION_ID, GetId());
    SendParentMessage(action);
    @ BFM_ACTION_ID
    Int32 ID of the dialog element that triggered the action.
    Definition: gui.h:747
    @ BFM_ACTION
    One of the child elements made any action:
    Definition: gui.h:746
    // This example changes the color of the user area depending on the focus.
    void DrawMsg(Int32 x1, Int32 y1, Int32 x2, Int32 y2, const BaseContainer& msg)
    {
    OffScreenOn();
    SetClippingRegion(x1, y1, x2, y2);
    // check if the user area has the focus
    if (this->HasFocus())
    DrawSetPen(Vector(0.0, 0.0, 1.0));
    else
    DrawSetPen(Vector(0.0, 0.2, 0.8));
    DrawRectangle(x1, y1, x2, y2);
    }

    Timer

    A user area can use an internal timer that calls GeUserArea::Timer() periodically.

    • GeUserArea::SetTimer(): Initializes the timer clock.
    // This example initializes the GeUserArea and sets the timer.
    Bool Init()
    {
    this->SetTimer(500); // value in ms
    return true;
    }
    // This example implements GeUserArea::Timer().
    // The function is called in the interval defined with GeUserArea::SetTimer().
    void Timer(const BaseContainer& msg)
    {
    ApplicationOutput("Timer tick");
    }

    User Interaction

    A user area can handle user interaction events by implementing GeUserArea::InputEvent(). The following functions are used to get more detailed information on the current event:

    • GeUserArea::GetInputState(): Gets the current state of the given input device.
    • GeUserArea::GetInputEvent(): Gets the next input event for the given device from the event queue.
    • GeUserArea::KillEvents(): Flushes all events from the window message queue.
    • GeUserArea::IsHotkeyDown(): Returns true if the given hotkey is pressed. see HOTKEYFLAGS.

    A special operation is a mouse drag event inside the user area. Such a mouse drag is initiated in reaction to certain user interaction using these functions:

    • GeUserArea::MouseDragStart(): Starts the mouse drag operation.
    • GeUserArea::MouseDrag(): Polls the mouse during a drag.
    • GeUserArea::MouseDragEnd(): Ends a mouse drag operation.
    // This example handles a mouse drag event of the left mouse button.
    const Int32 device = msg.GetInt32(BFM_INPUT_DEVICE);
    const Int32 channel = msg.GetInt32(BFM_INPUT_CHANNEL);
    // check if this is a mouse event triggered by the left mouse button
    if (device == BFM_INPUT_MOUSE && channel == BFM_INPUT_MOUSELEFT)
    {
    BaseContainer channels;
    BaseContainer state;
    Int32 startX = msg.GetInt32(BFM_INPUT_X);
    Int32 startY = msg.GetInt32(BFM_INPUT_Y);
    Float deltaX = 0.0f;
    Float deltaY = 0.0f;
    Global2Local(&startX, &startY);
    // start mouse drag
    MouseDragStart(BFM_INPUT_MOUSELEFT, (Float)startX, (Float)startY, MOUSEDRAGFLAGS::DONTHIDEMOUSE);
    // handle mouse drag
    while (MouseDrag(&deltaX, &deltaY, &channels) == MOUSEDRAGRESULT::CONTINUE)
    {
    // get state of the left mouse button
    break;
    // check if the mouse button is not pressed
    if (state.GetInt32(BFM_INPUT_VALUE) == 0)
    break;
    // print something if the mouse has moved
    if (deltaX != 0.0 || deltaY != 0.0)
    ApplicationOutput("Mouse Drag");
    }
    MouseDragEnd();
    return true;
    }
    PyArena _PyASTOptimizeState * state
    Definition: compile.h:99
    CONTINUE
    Drag still in progress.
    Definition: ge_prepass.h:2
    DONTHIDEMOUSE
    Show mouse pointer during drag.
    Definition: ge_prepass.h:1
    @ BFM_INPUT_MOUSELEFT
    Left mouse button.
    Definition: gui.h:716
    @ BFM_INPUT_VALUE
    Int32 Value of the input channel (true/false or a Int32 value, e.g. for scroll wheel data).
    Definition: gui.h:726
    @ BFM_INPUT_CHANNEL
    Int32 Contains the key or mouse button. See also KEY.
    Definition: gui.h:715
    Bool GetInputState(Int32 askdevice, Int32 askchannel, BaseContainer &res)
    maxon::Float Float
    Definition: ge_sys_math.h:57
    Definition: grammar.h:37

    Drag and Drop

    The user can drag and drop various elements onto a user area. The user area is informed about this event through messages sent to GeUserArea::Message(). These functions are used to react to those messages:

    • GeUserArea::CheckDropArea(): Returns true if the drag event is over the user area.
    • GeUserArea::GetDragPosition(): Gets the coordinates of the drag event.
    • GeUserArea::GetDragObject(): Gets the object that is dragged.
    • GeUserArea::SetDragDestination(): Sets the cursor that should be displayed. See MOUSE.

    See also Drag and Drop.

    // This example handles a drag and drop event in GeUserArea::Message().
    {
    // check drag area
    if (!CheckDropArea(msg, true, true))
    break;
    void* data = nullptr;
    // get the drag data
    if (!GetDragObject(msg, &type, &data))
    return false;
    // check if an C4DAtom was dragged
    return false;
    // get content
    const AtomArray* const elements = static_cast<AtomArray*>(data);
    // check content
    if (!elements->GetIndex(0))
    return false;
    // check if drag has finished
    if (msg.GetInt32(BFM_DRAG_FINISHED))
    {
    // loop through all elements of the AtomArray
    for (Int32 i = 0; i < elements->GetCount(); ++i)
    {
    const C4DAtom* const atom = elements->GetIndex(i);
    // check if the given C4DAtom is a BaseList2D element
    if (atom && atom->IsInstanceOf(Tbaselist2d))
    {
    const BaseList2D* const baselistObject = static_cast<const BaseObject*>(atom);
    ApplicationOutput("Dragged object: " + baselistObject->GetName());
    }
    }
    }
    else
    {
    // if in drag, show different mouse cursor
    return SetDragDestination(MOUSE_POINT_HAND);
    }
    return true;
    }
    Py_ssize_t i
    Definition: abstract.h:645
    #define atom
    Definition: graminit.h:72
    @ BFM_DRAG_FINISHED
    Bool Drag finished.
    Definition: gui.h:797
    @ DRAGTYPE_ATOMARRAY
    AtomArray.
    Definition: gui.h:786
    @ BFM_DRAGRECEIVE
    Drag receive. (See DragAndDrop.)
    Definition: gui.h:774
    #define Tbaselist2d
    2D list.
    Definition: ge_prepass.h:995
    PyObject ** type
    Definition: pycore_pyerrors.h:34

    It is also possible to start a drag and drop operation from a user area. This is typically done in reaction to some user interaction.

    • GeUserArea::HandleMouseDrag(): Starts a drag and drop operation.
    // This example starts a drag and drop operation.
    Bool InputEvent(const BaseContainer& msg)
    {
    const Int32 device = msg.GetInt32(BFM_INPUT_DEVICE);
    const Int32 channel = msg.GetInt32(BFM_INPUT_CHANNEL);
    if (device == BFM_INPUT_MOUSE)
    {
    if (channel == BFM_INPUT_MOUSELEFT)
    {
    // drag a color
    Vector red(1.0, 0.0, 0.0);
    // start a drag & drop event of dragging a color value
    if (HandleMouseDrag(msg, DRAGTYPE_RGB, &red, 0))
    return true;
    }
    }
    return false;
    }
    @ DRAGTYPE_RGB
    RGB color.
    Definition: gui.h:788

    Parent Message

    A user area can send messages to its parent GeDialog. This is typically done to inform the dialog that some user interaction occurred and that the managed values changed.

    • GeUserArea::SendParentMessage(): Sends a message to the parent dialog.

    See GUI and Interaction Messages Manual.

    // This example sends the BFM_ACTION message from a GeUserArea to the parent GUI element.
    // This message can be caught in GeDialog::Message() or GeDialog::Command().
    BaseContainer action(BFM_ACTION);
    action.SetInt32(BFM_ACTION_ID, GetId());
    SendParentMessage(action);

    Drawing

    Drawing Basics

    The central task of a user area is to draw something to Cinema 4D's user interface. The drawing operations have to happen inside the GeUserArea::DrawMsg() function.

    The drawing operation can be triggered with:

    • GeUserArea::Redraw(): Forces the user area to redraw itself.
    • GeUserArea::LayoutChanged(): Informs Cinema 4D that the user area has new dimensions. This will result in a redraw.

    Drawing Operations

    The following functions can be used to draw inside the canvas provided by the user area. For more advanced drawing operations one can use a GeClipMap and GeUserArea::DrawBitmap().

    The color and opacity settings are handled with:

    • GeUserArea::GetColorRGB(): Gets the color value for the given color ID. See c4d_colors.h.
    • GeUserArea::DrawSetPen(): Sets the currently used drawing color.
    • GeUserArea::DrawSetOpacity(): Sets the opacity used in the following drawing operations.
    // This example draws a white background and a black text.
    // draw a white background
    DrawSetPen(Vector(1.0f));
    DrawRectangle(x1, y1, x2, y2);
    // draw some text
    DrawSetTextCol(Vector(0.0f), Vector(1.0f));
    DrawText("Hello World!"_s, 0, 0, DRAWTEXT_HALIGN_LEFT);
    #define DRAWTEXT_HALIGN_LEFT
    Align to the left.
    Definition: c4d_gui.h:189

    Different styles used with various drawing functions are (::LINESTYLE):

    • LINESTYLE::NORMAL
    • LINESTYLE::DOTTED
    • LINESTYLE::DASHED
    • LINESTYLE::DASHED_INV

    These functions draw primitive shapes:

    • GeUserArea::DrawLine(): Draws a line.
    • GeUserArea::DrawRectangle(): Draws a rectangle.
    • GeUserArea::DrawFrame(): Draws a frame.
    • GeUserArea::DrawBezierLine(): Draws a Bezier line.
    • GeUserArea::DrawBezierFill(): Draws a Bezier line and fills the area.
    • GeUserArea::DrawPolyLine(): Draws a poly line.
    • GeUserArea::DrawPolyFill(): Draws a poly line and fills the area.
    • GeUserArea::DrawEllipseLine(): Draws an ellipse.
    • GeUserArea::DrawEllipseFill(): Draws an ellipse and fills the area.
    // This example draws shapes in a GeUserArea.
    // draw base
    {
    const maxon::Vector2d center(300, 60);
    const maxon::Vector2d radius(40, 40);
    DrawSetPen(Vector(1, 1, 0));
    DrawEllipseFill(center, radius);
    DrawSetPen(Vector(0, 0, 0));
    DrawEllipseLine(center, radius);
    }
    // draw eyes
    DrawSetPen(Vector(0, 0, 0));
    {
    const maxon::Vector2d center(285, 50);
    const maxon::Vector2d radius(3, 3);
    DrawEllipseFill(center, radius);
    }
    {
    const maxon::Vector2d center(315, 50);
    const maxon::Vector2d radius(3, 3);
    DrawEllipseFill(center, radius);
    }
    // draw mouth
    {
    BezierPoint p;
    p.c1 = Vector2d(280, 90);
    p.c2 = Vector2d(320, 90);
    p.p = Vector2d(320, 70);
    DrawBezierLine(Vector2d(280, 70), maxon::ToSingletonBlock(p), false, 1.0, LINESTYLE::NORMAL);
    }
    unsigned char * p
    Definition: floatobject.h:87
    #define MAXON_SCOPE
    Definition: apibase.h:2891
    Block< T > ToSingletonBlock(T &value)
    Definition: block.h:984
    NORMAL
    Definition: lib_birender.h:2
    maxon::Vec2< maxon::Float64, 1 > Vector2d
    Definition: ge_math.h:142

    A BaseBitmap can both be drawn to the canvas and filled with the current pen:

    • GeUserArea::DrawBitmap(): Draws a BaseBitmap. For effects see BMP.
    • GeUserArea::FillBitmapBackground(): Fills the given BaseBitmap with the current pen color.

    See also BaseBitmap Manual.

    // This example fills a GeClipMap and draws the resulting BaseBitmap in the user area.
    AutoAlloc<GeClipMap> clipMap;
    if (clipMap)
    {
    // get monospaced font
    BaseContainer font;
    GeClipMap::GetDefaultFont(GE_FONT_DEFAULT_MONOSPACED, &font);
    clipMap->Init(200, 50, 32);
    clipMap->BeginDraw();
    // fill background
    clipMap->SetColor(255, 255, 255, 255);
    clipMap->FillRect(0, 0, 200, 50);
    // draw text
    clipMap->SetFont(&font, 20.0);
    clipMap->SetColor(0, 0, 0, 255);
    clipMap->TextAt(0, clipMap->GetTextHeight(), "This is some text.");
    clipMap->EndDraw();
    // get bitmap
    BaseBitmap* const bitmap = clipMap->GetBitmap();
    if (bitmap)
    {
    // draw bitmap
    const Int32 width = bitmap->GetBw();
    const Int32 height = bitmap->GetBh();
    DrawBitmap(bitmap, 0, 0, width, height, 0, 0, width, height, BMP_NORMAL);
    }
    }
    @ BMP_NORMAL
    Standard scaling by the operating system. Fast but low quality when using uneven scaling factors.
    Definition: gui.h:171
    @ GE_FONT_DEFAULT_MONOSPACED
    The Cinema 4D monospaced font.
    Definition: lib_clipmap.h:121
    unsigned long Py_ssize_t width
    Definition: pycore_traceback.h:88

    The border style of the user area is defined with:

    • GeUserArea::DrawBorder(): Draws a border with the given style, see BORDER.
    • GeUserArea::GetBorderSize(): Gets the space required to draw a border. Typically used with GeUserArea::GetMinSize().
    // This example draws a round border for the GeUserArea.
    DrawBorder(BORDER_ROUND, 0, 0, GetWidth(), GetHeight());
    @ BORDER_ROUND
    Border with round corners.
    Definition: gui.h:271

    Text is drawn with these functions:

    • GeUserArea::DrawText(): Draws the given String.
    • GeUserArea::DrawSetTextCol(): Sets the text foreground and background color.
    • GeUserArea::DrawSetFont(): Sets the text font, see FONT.
    • GeUserArea::DrawGetTextWidth(): Returns the width in pixels of the given String.
    • GeUserArea::DrawGetFontHeight(): Returns the height in pixels of the given String.
    • GeUserArea::DrawGetTextWidth_ListNodeName(): Returns the width in pixels of the name of the given BaseList2D.
    • GeUserArea::DrawGetFontBaseLine(): Returns the base line of the current font.
    • GeUserArea::DrawSetTextRotation(): Sets the text rotation.
    // This example draws some text and a line under that text.
    const String text { "Hello World!" };
    const Int32 left = 100;
    // draw text
    DrawSetTextCol(Vector(0.0f), Vector(1.0f));
    DrawSetFont(FONT_MONOSPACED);
    DrawText(text, left, 0, DRAWTEXT_HALIGN_LEFT);
    // draw a line
    const Int32 baseline = DrawGetFontBaseLine() + 1;
    const Int32 length = DrawGetTextWidth(text);
    DrawSetPen(Vector(0.5f));
    DrawLine(left, baseline, left + length, baseline);
    @ FONT_MONOSPACED
    Monospaced font.
    Definition: gui.h:25
    PyWideStringList Py_ssize_t length
    Definition: initconfig.h:448
    PyObject * text
    Definition: pycore_traceback.h:70

    A user area can support a dynamic fading effect that is typically used to change the background color of the gadget after the cursor moved over it:

    • GeUserArea::ActivateFading(): Activates the dynamic fading. The message ::BFM_FADE will be sent to the user area.
    • GeUserArea::AdjustColor(): Calculates the new color while fading.

    See also Fading.

    // This example shows a GeUserArea that is "fading".
    // When the cursor is over the user area the fading is activated.
    // Cinema 4D will then send the message BFM_FADE to the user area so
    // it can interpolate a color and use this color to redraw itself.
    class FadingUserArea : public GeUserArea
    {
    public:
    FadingUserArea() { };
    ~FadingUserArea() { };
    Int32 Message(const BaseContainer& msg, BaseContainer& result)
    {
    // messages are identified by the BaseContainer ID
    switch (msg.GetId())
    {
    {
    // cursor is over the user area
    // start fading
    ActivateFading(100);
    return true;
    }
    case BFM_FADE:
    {
    // receive fade message and update the COLOR_BG used in DrawMsg()
    const Float percentage = msg.GetFloat(BFM_FADE);
    AdjustColor(COLOR_BG, COLOR_BG_HIGHLIGHT, percentage);
    // redraw using the updated COLOR_BG
    Redraw();
    return true;
    }
    }
    return GeUserArea::Message(msg, result);
    }
    void DrawMsg(Int32 x1, Int32 y1, Int32 x2, Int32 y2, const BaseContainer& msg)
    {
    OffScreenOn();
    SetClippingRegion(x1, y1, x2, y2);
    // draw background with COLOR_BG
    DrawSetPen(COLOR_BG);
    DrawRectangle(x1, y1, x2, y2);
    // draw text
    DrawSetTextCol(COLOR_CONSOLE_TEXT, COLOR_TRANS);
    DrawSetFont(FONT_MONOSPACED);
    DrawText("User Area"_s, 0, 0, DRAWTEXT_HALIGN_LEFT);
    }
    };
    @ COLOR_BG_HIGHLIGHT
    Definition: c4d_colors.h:329
    @ COLOR_TRANS
    Definition: c4d_colors.h:14
    @ COLOR_CONSOLE_TEXT
    Definition: c4d_colors.h:94
    @ COLOR_BG
    Definition: c4d_colors.h:16
    @ BFM_FADE
    Definition: gui.h:1009

    It is also possible to be informed when the cursor leaves the user area:

    • RemoveLastCursorInfo(): Registers a callback function that is called when the cursor leaves the user area. The function typically sends the message ::BFM_CURSORINFO_REMOVE back to the user area.
    // This example user area registers a callback function with RemoveLastCursorInfo().
    // This function is called when the cursor leaves the user area. It is used to send the
    // message BFM_CURSORINFO_REMOVE back to the user area to inform it about the event.
    // declarations
    static void RemoveCursorInfo();
    class RemoveCursorUserArea;
    static RemoveCursorUserArea* g_userArea = nullptr; // static variable storing pointer to a user area
    // user area will display a different color depending if the cursor is over the area or not
    class RemoveCursorUserArea : public GeUserArea
    {
    public:
    RemoveCursorUserArea()
    {
    if (g_userArea == this)
    g_userArea = nullptr;
    };
    ~RemoveCursorUserArea() { };
    Int32 Message(const BaseContainer& msg, BaseContainer& result)
    {
    // messages are identified by the BaseContainer ID
    switch (msg.GetId())
    {
    {
    // register RemoveCursorInfo() callback
    g_userArea = this;
    RemoveLastCursorInfo(RemoveCursorInfo);
    _cursorInside = true;
    Redraw();
    return true;
    }
    {
    // message "BFM_CURSORINFO_REMOVE" sent by RemoveCursorInfo()
    _cursorInside = false;
    Redraw();
    break;
    }
    }
    return GeUserArea::Message(msg, result);
    }
    void DrawMsg(Int32 x1, Int32 y1, Int32 x2, Int32 y2, const BaseContainer& msg)
    {
    OffScreenOn();
    SetClippingRegion(x1, y1, x2, y2);
    // gadget color is controlled by the cursor position
    if (_cursorInside)
    DrawSetPen(Vector(1.0, 0.0, 0.0));
    else
    DrawSetPen(Vector(0.0, 1.0, 0.0));
    DrawRectangle(x1, y1, x2, y2);
    }
    private:
    Bool _cursorInside = false; // set to true if the cursor is over the user area
    };
    // function will be called by the user area when the cursor left its area
    static void RemoveCursorInfo()
    {
    if (g_userArea == nullptr)
    return;
    // send message to the user area
    BaseContainer bc;
    g_userArea->Message(BaseContainer(BFM_CURSORINFO_REMOVE), bc);
    }
    @ BFM_CURSORINFO_REMOVE
    Sent when mouse cursor has left a user area.
    Definition: gui.h:577
    Bool RemoveLastCursorInfo(LASTCURSORINFOFUNC func)

    Clipping

    Clipping is used to limit drawing operations to certain areas:

    • GeUserArea::SetClippingRegion(): Specifies the clipping region for the drawing functions.
    • GeUserArea::ClearClippingRegion(): Clears the clipping region set with GeUserArea::SetClippingRegion().
    • GeUserArea::OffScreenOn(): Enables double buffering to avoid blinking and flickering effects. Automatically sets the clipping area to the whole user area or the given region.
    // This example draws a white rectangle in the given region.
    void DrawMsg(Int32 x1, Int32 y1, Int32 x2, Int32 y2, const BaseContainer& msg)
    {
    OffScreenOn();
    SetClippingRegion(x1, y1, x2, y2);
    DrawSetPen(Vector(1, 1, 1));
    DrawRectangle(x1, y1, x2, y2);
    }

    Miscellaneous

    Miscellaneous functions are:

    • GeUserArea::ScrollArea(): Scrolls the user area.
    • GeUserArea::GetPixelRatio(): Returns the screen pixel ratio to indicate Retina displays.

    Coordinate Transformation

    These functions are used to transform coordinates into different spaces:

    • GeUserArea::Local2Global(): Transforms local coordinates to global window coordinates.
    • GeUserArea::Global2Local(): Transforms global window coordinates to local coordinates.
    • GeUserArea::Local2Screen(): Transforms local coordinates to screen coordinates.
    • GeUserArea::Screen2Local(): Transforms screen coordinates to local coordinates.
    // This example creates a pop up menu when the right mouse button was pressed.
    Bool InputEvent(const BaseContainer& msg)
    {
    const Int32 device = msg.GetInt32(BFM_INPUT_DEVICE);
    const Int32 channel = msg.GetInt32(BFM_INPUT_CHANNEL);
    // check if this is a mouse event triggered by the left mouse button
    if (device == BFM_INPUT_MOUSE && channel == BFM_INPUT_MOUSERIGHT)
    {
    // get the cursor position
    Int32 x = msg.GetInt32(BFM_INPUT_X);
    Int32 y = msg.GetInt32(BFM_INPUT_Y);
    Global2Local(&x, &y);
    Local2Screen(&x, &y);
    // define pop up menu
    BaseContainer bc;
    bc.InsData(5159, "CMD"); // cube
    bc.InsData(0, String());
    bc.InsData(5160, "CMD"); // sphere
    // show pop up menu
    ShowPopupMenu(GetDialog()->Get(), x, y, bc);
    return true;
    }
    return false;
    }
    PyObject * x
    Definition: bytesobject.h:38
    @ BFM_INPUT_MOUSERIGHT
    Right mouse button.
    Definition: gui.h:717
    Int32 ShowPopupMenu(CDialog *cd, Int32 screenx, Int32 screeny, const BaseContainer &bc, Int32 flags=POPUP_RIGHT|POPUP_EXECUTECOMMANDS|POPUP_ALLOW_FILTERING, Int32 *res_mainid=nullptr)
    const Class< R > & Get(const Id &cls)
    Definition: objectbase.h:2090

    Further Reading