Tutorial 6 - Drag Painter

This tutorial introduces drag painters with the "drag_painter" program. The program consists of a window where the user can draw lines. A drag painter is used to draw the line while the user is dragging the mouse. This program is made up of five files - the source and header for the object that contains the window, the source and header for the drag painter widget and the source that contains the function main.

The DragWidget object - DragWidget.cc and DragWidget.h

The object that implements a drag painter is called DragWidget and is derived from JXScrollableWidget

DragWidget source file:

/******************************************************************************
 DragWidget.cc

    BASE CLASS = JXWindowDirector

    Written by Glenn Bach - 1997.

 ******************************************************************************/

#include "DragWidget.h"
#include <JXApplication.h>
#include <JXWidget.h>
#include <JXWindowPainter.h>
#include <JXDragPainter.h>
#include <JXColormap.h>
#include <jXGlobals.h>
#include <jAssert.h>

/******************************************************************************
 Constructor

 ******************************************************************************/

DragWidget::DragWidget
    (
    JXScrollbarSet* scrollbarSet,
    JXContainer* enclosure,
    const HSizingOption hSizing,
    const VSizingOption vSizing,
    const JCoordinate x,
    const JCoordinate y,
    const JCoordinate w,
    const JCoordinate h
    )
    :
    JXScrollableWidget(scrollbarSet, enclosure, hSizing, vSizing, x, y, w, h)
{
    // This changes our Bounds, independent of what part of us
    // is visible (our Frame).
    SetBounds(500, 400);

    // This array keeps track of the points that define the beginning and
    // ending of each line the is draw in the window.

    // See JCollection.h, JOrderedSet.h, and JArray.h for functionality

    itsPoints = new JArray<JPoint>;
    assert( itsPoints != NULL );
}

/******************************************************************************
 Destructor

 ******************************************************************************/

DragWidget::~DragWidget()
{
    // Unlike widgets, which are automatically deleted by the framework,
    // we must delete this JArray since it is a private instance variable.
    delete itsPoints;
}

/******************************************************************************
 Draw (virtual protected)

    This gets called by the event loop every time the Widget needs to
    be redrawn.

 ******************************************************************************/

void
DragWidget::Draw
    (
    JXWindowPainter& p,
    const JRect&     rect
    )
{
    // Set pen color
    p.SetPenColor((GetColormap())->GetBlackColor());

    // Find out how many points there are
    // There are count/2 lines
    JSize count = itsPoints->GetElementCount();

    // Loop through the points by twos
    for (JSize i = 1; i <= count; i += 2)
        {
        // We need to specify that this is a JPainter function because
        // JXWindowPainter has this function in a different form
        p.JPainter::Line(itsPoints->GetElement(i), itsPoints->GetElement(i+1));
        }
}

/******************************************************************************
 HandleMouseDown (virtual protected)

    This gets called by the event loop every time a mouse button is pressed.

    pt is where the mouse was clicked, in Bounds coordinates.

    button is the index of the mouse button being pressed.

    clickCount is the number of times that this button has been pressed
    in rapid succession.

    buttonStates tells the state of all the mouse buttons.
    Refer to JXButtonStates.h for more information.

    modifiers contains information about modifier keys like Shift and
    Control.  Refer to JXKeyModifiers.h for more information.

 ******************************************************************************/

void
DragWidget::HandleMouseDown
    (
    const JPoint&            pt,
    const JXMouseButton        button,
    const JSize                clickCount,
    const JXButtonStates&    buttonStates,
    const JXKeyModifiers&    modifiers
    )
{
    // Check to see if the left button was pressed
    if (button == kJXLeftButton)
        {
        // Create the drag painter to draw the rubber-band like lines
        JPainter* p = CreateDragInsidePainter();

        // Start the first line
        p->Line(pt, pt);
        }

    // Initialize the current points
    itsStartPt = itsPrevPt = pt;
}

/******************************************************************************
 HandleMouseDrag (virtual protected)

    This gets called as often as possible by the event loop as long as
    a mouse button is pressed.

    pt is where the mouse is, in Bounds coordinates.

    buttonStates tells the state of all the mouse buttons.
    Refer to JXButtonStates.h for more information.

    modifiers contains information about modifier keys like Shift and
    Control.  Refer to JXKeyModifiers.h for more information.

 ******************************************************************************/

void
DragWidget::HandleMouseDrag
    (
    const JPoint&            pt,
    const JXButtonStates&    buttonStates,
    const JXKeyModifiers&    modifiers
    )
{
    // Check to see if the window was scrolled
    const JBoolean scrolled = ScrollForDrag(pt);

    // Get the drag painter that we created in mouse down
    JPainter* p = GetDragPainter();

    // Make sure that the left button is pressed,
    // that we have moved,
    // and that a drag painter exists
    if (buttonStates.left() && pt != itsPrevPt && p != NULL) // p is NULL for multiple click
        {

        // Draw line depending on whether or not we scrolled
        if (!scrolled)
            {
            p->Line(itsStartPt, itsPrevPt);
            }
        p->Line(itsStartPt, pt);
        }

    // Remember the current point
    itsPrevPt = pt;
}

/******************************************************************************
 HandleMouseUp (virtual protected)

    This gets called by the event loop every time a mouse button is released.

    pt is where the mouse was released, in Bounds coordinates.

    button is the index of the mouse button being pressed.

    buttonStates tells the state of all the mouse buttons.
    Refer to JXButtonStates.h for more information.

    modifiers contains information about modifier keys like Shift and
    Control.  Refer to JXKeyModifiers.h for more information.

 ******************************************************************************/

void
DragWidget::HandleMouseUp
    (
    const JPoint&            pt,
    const JXMouseButton        button,
    const JXButtonStates&    buttonStates,
    const JXKeyModifiers&    modifiers
    )
{
    // Get the drag painter that we created in mouse down
    JPainter* p = GetDragPainter();

    // Make sure that the left button is pressed,
    // and that a drag painter exists
    if (button == kJXLeftButton && p != NULL)    // p is NULL for multiple click
        {
        // Erase the last line that was drawn
        p->Line(itsStartPt, itsPrevPt);

        // Delete the drag painter
        DeleteDragPainter();

        // Add this set of points to our JArray
        itsPoints->AppendElement(itsStartPt);
        itsPoints->AppendElement(itsPrevPt);

        // Tell the widget to redraw itself
        Refresh();
        }
}

/******************************************************************************
 HandleKeyPress (virtual)

    This gets called by the event loop every time a key is pressed.

    If the key that was pressed had an ASCII equivalent, then 'key'
    contains the ASCII value.  Otherwise, 'key' contains the X KeySym
    value, as defined in X11/keysym.h.

    modifiers contains information about modifier keys like Shift and
    Control.  Refer to JXKeyModifiers.h for more information.

 ******************************************************************************/

void
DragWidget::HandleKeyPress
    (
    const int             key,
    const JXKeyModifiers& modifiers
    )
{
    // Check if the 'c' key was pressed
    // If so, we want to clear the window
    if (key == 'c')
        {
        // remove all of the points from the JArray
        itsPoints->RemoveAll();

        // Redraw
        Refresh();
        }

    // Check if the 'q' key was pressed
    else if (key == 'q')
        {
        // Quit the application if 'q' was pressed
        (JXGetApplication())->Quit();
        }

    // If anything else was pressed, pass it up the inheritance tree
    else
        {
        JXScrollableWidget::HandleKeyPress(key,modifiers);
        }
}
 

DragWidget header file:

/******************************************************************************
 DragWidget.h

    Interface for the DragWidget class

    Written by Glenn Bach - 1997.

 ******************************************************************************/

#ifndef _H_DragWidget
#define _H_DragWidget

#include <JXScrollableWidget.h>
#include <JArray.h>

class DragWidget : public JXScrollableWidget
{
public:

    DragWidget(JXScrollbarSet* scrollbarSet, JXContainer* enclosure,
               const HSizingOption hSizing, const VSizingOption vSizing,
               const JCoordinate x, const JCoordinate y,
               const JCoordinate w, const JCoordinate h);

    virtual ~DragWidget();

    virtual void    HandleKeyPress(const int key,
                                   const JXKeyModifiers& modifiers);

protected:

    virtual void    Draw(JXWindowPainter& p, const JRect& rect);
    virtual void    HandleMouseDown(const JPoint& pt, const JXMouseButton button,
                                    const JSize clickCount,
                                    const JXButtonStates& buttonStates,
                                    const JXKeyModifiers& modifiers);
    virtual void    HandleMouseDrag(const JPoint& pt, const JXButtonStates& buttonStates,
                                    const JXKeyModifiers& modifiers);
    virtual void    HandleMouseUp(const JPoint& pt, const JXMouseButton button,
                                  const JXButtonStates& buttonStates,
                                  const JXKeyModifiers& modifiers);

private:

    // used during drag

    JPoint    itsStartPt;
    JPoint    itsPrevPt;

    JArray<JPoint>* itsPoints;

private:

    // not allowed

    DragWidget(const DragWidget& source);
    const DragWidget& operator=(const DragWidget& source);
};

#endif

The DragWidgetDir object - DragWidgetDir .cc and

DragWidgetDir .h

The object that holds the window is a DragWidgetDir object which is derived from JXWindowDirector.

DragWidgetDir source file:

/******************************************************************************
 DragWidgetDir.cc

    BASE CLASS = JXWindowDirector

    Written by Glenn Bach - 1997.

 ******************************************************************************/

#include "DragWidgetDir.h"
#include "DragWidget.h"
#include <JXWindow.h>
#include <JXScrollbarSet.h>
#include <jAssert.h>

/******************************************************************************
 Constructor

 ******************************************************************************/

DragWidgetDir::DragWidgetDir
    (
    JXDirector* supervisor
    )
    :
    JXWindowDirector(supervisor)
{
    BuildWindow();
}

/******************************************************************************
 Destructor

 ******************************************************************************/

DragWidgetDir::~DragWidgetDir()
{
}

/******************************************************************************
 BuildWindow
          This is a convenient and organized way of putting all of the initial
     elements into a window. This will keep the constructor less cluttered.

 ******************************************************************************/

void
DragWidgetDir::BuildWindow()
{
     // Create the window
    JXWindow* window = new JXWindow(this, 300,200, "Drag Painter Program");
    assert( window != NULL );
 
    // Give the window to the director
    SetWindow(window);
 
    // Set the window sizing
    window->SetMinSize(300,200);
    window->SetMaxSize(800,600);
 
    // Create the scrollbar set
    JXScrollbarSet* scrollbarSet =
        new JXScrollbarSet(window,
            JXWidget::kHElastic, JXWidget::kVElastic, 0,0, 300,200);
    assert( scrollbarSet != NULL );

    // Create the custom widget with the scrollbarset as its enclosure
    DragWidget* widget =
        new DragWidget(scrollbarSet, scrollbarSet->GetScrollEnclosure(),
            JXWidget::kHElastic, JXWidget::kVElastic,
            0, 0, 10, 10);
    assert( widget != NULL );
 
    // Fit the widget within the scrollbarset enclosure
    widget->FitToEnclosure(kTrue, kTrue);
}
 

DragWidgetDir header file:

/******************************************************************************
 DragWidgetDir.h

    Interface for the DragWidgetDir class

    Written by Glenn Bach - 1997.

 ******************************************************************************/

#ifndef _H_DragWidgetDir
#define _H_DragWidgetDir

#include <JXWindowDirector.h>

class DragWidgetDir : public JXWindowDirector
{
public:

    DragWidgetDir(JXDirector* supervisor);

    virtual ~DragWidgetDir();

private:

    void BuildWindow();

    // not allowed

    DragWidgetDir(const DragWidgetDir& source);
    const DragWidgetDir& operator=(const DragWidgetDir& source);
};

#endif

The function main - drag_painter.cc

/******************************************************************************
 drag_painter.cc
 
 Written by Glenn Bach - 1997.

 ******************************************************************************/

#include "DragWidgetDir.h"
#include <JXApplication.h>
#include <jAssert.h>

/******************************************************************************
 main

 ******************************************************************************/

int
main
    (
    int      argc,
    char*    argv[]
    )
{
    // Create the application
    JXApplication* app = new JXApplication(&argc, argv);
    assert( app != NULL );

    // Create the window director
    DragWidgetDir* mainDir = new DragWidgetDir(app);
    assert( mainDir != NULL );

    // Activate the window director
    mainDir->Activate();
 
    // Start the event loop
    app->Run();
    return 0;
}