#include <iostream>
#include <math.h>
#include <qwidget.h>
#include <qpainter.h>
#include <qdragobject.h>
#include <qglobal.h>

using std::cout;
using std::endl;

#include "render2d.h"
#include "chemdata.h"
#include "drawable.h"
#include "molecule.h"
#include "text.h"
#include "defs.h"
#include "xdc_event.h"

void Render2D::mousePressEvent(QMouseEvent *e1) {

    bool allowedit = false;
    moved = false;

    DPoint tmp_pt(e1->x(), e1->y());

    if (mode > 100)
      c->StartUndo(mode, 0);   // BMS: StartUndo does nothing with the point - don't copy!
    //cout << "Click" << endl;
    // update button state
    if (e1->button() == LeftButton)
        mouse1down = true;
    if (e1->button() == RightButton) {
        mouse3down = true;
    }
    //cout << "start at " << e1->x() << "," << e1->y() << endl;

    // MODE_TEXT: call special function to handle text events
    if (mode == MODE_TEXT) {
        DrawText_mousePressEvent(e1);
        return;
    }

    // MODE_SELECT: start multiple selection
    if ( (mode == MODE_SELECT) && (mouse1down) ) {
        if ( ( highlightpoint == 0) && (highlightobject == 0) ) {
            selectOrigin = e1->pos();
            mode = MODE_SELECT_MULTIPLE;
            return;
        } else {
            cout << "Should move." << endl;
            if (highlightpoint == 0) {
                mode = MODE_SELECT_MOVE_OBJECT;
            } else {
                if (highlightpoint->other != 0) {
                    mode = MODE_DRAWLINE_DRAWING;
                    c->Erase(highlightpoint->otherBond);
                    startpoint = highlightpoint->other;
                    endpoint = 0;
                    highlightpoint = 0;
                    prev_mode = MODE_SELECT;
                } else {
                    mode = MODE_SELECT_MOVE_POINT;
                }
            }
        }
        return;
    }

    // set allowedit = true for appropriate modes
    if (mode == MODE_SELECT)
        allowedit = true;
    // get Drawable of nearest object
    DPoint *e = new DPoint;
    e->x = e1->x();
    e->y = e1->y();
    double distobj;
    Drawable *no = c->FindNearestObject(e, distobj);
    if (distobj > 5.0)
        no = 0;
    if (no != 0) {
        if ( (mode == MODE_DRAWLINE) &&
                (no->Type() == TYPE_BOND) )
            allowedit = true;
        if ( (mode == MODE_DRAWLINE_DASH) &&
                (no->Type() == TYPE_BOND) )
            allowedit = true;
        if ( (mode == MODE_DRAWLINE_UP) &&
                (no->Type() == TYPE_BOND) )
            allowedit = true;
        if ( (mode == MODE_DRAWLINE_DOWN) &&
                (no->Type() == TYPE_BOND) )
            allowedit = true;
    }
    // allowedit and BUTTON3: edit item under mouse
    if ( (allowedit) && (mouse3down) ) {
        if (highlightobject == 0)
            highlightobject = no;
        if (highlightobject != 0) {
            if (highlightobject->Type() == TYPE_TEXT) {
                setCursor(ibeamCursor);
                mode = MODE_TEXT;
                text_exists = true;
                localtext = (Text *)highlightobject;
                emit TextOn(localtext->getFont());
                repaint(false);
                return;
            }
            cout << "Will edit" << endl;
            highlightobject->Edit();
            highlightobject->Highlight(false);
            highlightobject = 0;
            if (mode == MODE_SELECT)
                setCursor(arrowCursor);
            else
                setCursor(crossCursor);
            mouse3down = false;
            repaint(false);
        }
        return;
    }

    // MODE_SELECT_MULTIPLE_SELECTED: either move, or deselect all
    if ( (mode == MODE_SELECT_MULTIPLE_SELECTED) && (mouse1down) ) {
        // check for move
        if (selectionBox.contains( e1->pos() )) {
            c->StartUndo(0,0);
            mode = MODE_SELECT_MOVE_MULTIPLE;
        } else {
            c->DeselectAll();
            mode = MODE_SELECT;
            repaint(false);
        }
    }

    // MODE_SELECT_MULTIPLE_SELECTED and Button3: Drag and Drop!
    if ( (mode == MODE_SELECT_MULTIPLE_SELECTED) && (mouse3down) ) {
        // check for move
        if (selectionBox.contains( e1->pos() )) {
            dragging = true;
        } else {
            c->DeselectAll();
            mode = MODE_SELECT;
            repaint(false);
        }
    }

    // MODE_SELECT_MULTIPLE_RESIZE: resize drawing
    if ( (mode == MODE_SELECT_MULTIPLE_RESIZE) && (mouse1down) ) {
        mode = MODE_SELECT_RESIZE_MULTIPLE;
    }

    // MODE_SELECT_MULTIPLE_ROTATE: rotate drawing
    if ( (mode == MODE_SELECT_MULTIPLE_ROTATE) && (mouse1down) ) {
        mode = MODE_SELECT_ROTATE_MULTIPLE;
        rotateOrigin.setX( (selectionBox.right() + selectionBox.left() - 2) / 2);
        rotateOrigin.setY( (selectionBox.bottom() + selectionBox.top()) / 2);
        prevangle = getAngle( rotateOrigin, e1->pos() );
    }

    // MODE_DRAWLINE (draw line tool selected), and left button.
    // This means we start drawing a line
    if ( (mode == MODE_DRAWLINE) && (mouse1down) ) {
        startpoint = highlightpoint; // both NULL if nothing selected
        highlightpoint = 0; // stop drawing highlight box
        if (startpoint == NULL) {
            startpoint = new DPoint;
            startpoint->set
            (e1->pos());
            endpoint = NULL;
        }
        mode = MODE_DRAWLINE_DRAWING;
    }

    // MODE_DRAWLINE_DASH (draw dashed line tool selected), and left button.
    // This means we start drawing a dashed line
    if ( (mode == MODE_DRAWLINE_DASH) && (mouse1down) ) {
        startpoint = highlightpoint; // both NULL if nothing selected
        highlightpoint = 0; // stop drawing highlight box
        if (startpoint == NULL) {
            startpoint = new DPoint;
            startpoint->set
            (e1->pos());
            endpoint = NULL;
        }
        mode = MODE_DRAWLINE_DASH_DRAWING;
    }

    // MODE_DRAWLINE_UP (draw stereo-up line tool selected), and left button.
    // This means we start drawing a line
    if ( (mode == MODE_DRAWLINE_UP) && (mouse1down) ) {
        startpoint = highlightpoint; // both NULL if nothing selected
        highlightpoint = 0; // stop drawing highlight box
        if (startpoint == NULL) {
            startpoint = new DPoint;
            startpoint->set
            (e1->pos());
            endpoint = NULL;
        }
        mode = MODE_DRAWLINE_UP_DRAWING;
    }

    // MODE_DRAWLINE_DOWN (draw stereo-down line tool selected), and left button.
    // This means we start drawing a line
    if ( (mode == MODE_DRAWLINE_DOWN) && (mouse1down) ) {
        startpoint = highlightpoint; // both NULL if nothing selected
        highlightpoint = 0; // stop drawing highlight box
        if (startpoint == NULL) {
            startpoint = new DPoint;
            startpoint->set
            (e1->pos());
            endpoint = NULL;
        }
        mode = MODE_DRAWLINE_DOWN_DRAWING;
    }

    // MODE_DRAWARROW (draw arrow tool selected), and left button.
    // This means we start drawing an arrow
    if ( (mode == MODE_DRAWARROW) && (mouse1down) ) {
        startpoint = new DPoint;
        startpoint->set
        (e1->pos());
        endpoint = NULL;
        mode = MODE_DRAWARROW_DRAWING;
    }

    // MODE_DRAWCURVEARROW (draw curve arrow tool selected), and left button.
    // This means we start drawing an arrow
    if ( (mode == MODE_DRAWCURVEARROW) && (mouse1down) ) {
        startpoint = new DPoint;
        startpoint->set
        (e1->pos());
        endpoint = NULL;
        mode = MODE_DRAWCURVEARROW_DRAWING;
    }

    // MODE_DRAWBRACKET (draw bracket tool selected), and left button.
    // This means we start drawing an bracket
    if ( (mode == MODE_DRAWBRACKET) && (mouse1down) ) {
        startpoint = new DPoint;
        startpoint->set
        (e1->pos());
        endpoint = NULL;
        mode = MODE_DRAWBRACKET_DRAWING;
    }

    // MODE_ERASE, and left button.  Erase highlighted object.
    if ( (mode == MODE_ERASE) && (mouse1down) ) {
        if (highlightobject == 0)
            return;
        c->Erase(highlightobject);
        highlightobject = 0;
        repaint(false);
    }
}

void Render2D::mouseReleaseEvent(QMouseEvent *e1) {
    emit signalModified();
    DPoint *tmp_pt;
    XDC_Event *evt;

    //cout << "Unclick" << endl;
    // update button state
    if (e1->button() == LeftButton)
        mouse1down = false;
    if (e1->button() == RightButton)
        mouse3down = false;
    //cout << "end at " << e1->x() << "," << e1->y() << endl;

    // MODE_TEXT: call special function to handle text events
    if (mode == MODE_TEXT) {
        DrawText_mouseReleaseEvent(e1);
        return;
    }

    // Control-LeftClick invokes Molecule Information window
    if ( (e1->button() == LeftButton) &&
	 ((e1->state() & ControlButton) == ControlButton) ) {
      tmp_pt = new DPoint(e1->pos());
      c->Tool(tmp_pt, MODE_TOOL_MOLECULE_INFO);
      repaint(false);
      return;
    }

    // MODE_TOOL_*: ChemData handles this, mostly
    if ( (mode > 600) && (mode < 699) ) {
      tmp_pt = new DPoint(e1->pos());
      c->Tool(tmp_pt, mode);
      repaint(false);
      //if (mode == MODE_TOOL_CLEANUPMOL) {
      setMode_Select();
      //}
      return;
    }

    // MODE_SELECT_MULTIPLE: finish multiple selection
    if ( (mode == MODE_SELECT_MULTIPLE) && (!mouse1down) ) {
      int tmp1;
      if (selectOrigin.x() > selectPrev.x()) {
	tmp1 = selectOrigin.x();
	selectOrigin.setX(selectPrev.x());
	selectPrev.setX(tmp1);
      }
      if (selectOrigin.y() > selectPrev.y()) {
	tmp1 = selectOrigin.y();
	selectOrigin.setY(selectPrev.y());
	selectPrev.setY(tmp1);
      }
      drawBox(selectOrigin, selectPrev, QColor(255,255,255));
      bool shiftdown = false;
      if ((e1->state() & ShiftButton) == ShiftButton)
	shiftdown = true;
      c->NewSelectRect(QRect(selectOrigin, selectPrev), shiftdown);
      selectionBox = c->selectionBox();
      if (selectionBox.left() < 999)
	mode = MODE_SELECT_MULTIPLE_SELECTED;
      else
	mode = MODE_SELECT;
      repaint(false);
    }

    // MODE_SELECT_MOVE_MULTIPLE: finish moving
    if ( (mode == MODE_SELECT_MOVE_MULTIPLE) && (!mouse1down) ) {
        mode = MODE_SELECT_MULTIPLE_SELECTED;
        c->FinishMove();
        repaint(false);
    }

    // MODE_SELECT_MOVE_OBJECT: finish moving
    if ( (mode == MODE_SELECT_MOVE_OBJECT) && (!mouse1down) ) {
        mode = MODE_SELECT;
        c->FinishMove();
        repaint(false);
    }

    // MODE_SELECT_MOVE_POINT: finish moving
    if ( (mode == MODE_SELECT_MOVE_POINT) && (!mouse1down) ) {
        mode = MODE_SELECT;
        c->FinishMove();
        repaint(false);
    }

    // MODE_SELECT_RESIZE_MULTIPLE: finish resizing
    if ( (mode == MODE_SELECT_RESIZE_MULTIPLE) && (!mouse1down) ) {
        mode = MODE_SELECT_MULTIPLE_SELECTED;
    }

    // MODE_SELECT_ROTATE_MULTIPLE: finish rotating
    if ( (mode == MODE_SELECT_ROTATE_MULTIPLE) && (!mouse1down) ) {
        mode = MODE_SELECT_MULTIPLE_SELECTED;
    }

    // MODE_DRAWLINE_DRAWING (drawing line), and left button.
    // Finish line
    if ( (mode == MODE_DRAWLINE_DRAWING) && (!mouse1down) ) {
      if (moved) {
	if (endpoint == NULL) {
	  endpoint = new DPoint;
	  endpoint->set
	    (e1->pos());
	}
	// submit this line/bond to ChemData
	if (startpoint != endpoint) {
	  evt = new XDC_Event(EVT_ADD_BOND);
	  evt->setStart(startpoint);
	  evt->setEnd(endpoint);
	  evt->setParam1(thick);
	  evt->setColor(currentColor);
	  emit XDCEventSignal(evt);
	  //c->addBond(startpoint, endpoint, thick, 1, currentColor);
	}
      }
      startpoint = NULL;
      endpoint = NULL;
      if (prev_mode == MODE_SELECT) {
	mode = MODE_SELECT;
	setCursor(arrowCursor);
	emit SignalSetStatusBar( tr("Select mode: left click on object to move, right click on object to edit") );
	prev_mode = 0;
      } else {
	mode = MODE_DRAWLINE;
      }
      repaint(false);
      return;
    }

    // MODE_DRAWLINE_DASH_DRAWING (drawing line), and left button.
    // Finish line
    if ( (mode == MODE_DRAWLINE_DASH_DRAWING) && (!mouse1down) ) {
        if (moved) {
            if (endpoint == NULL) {
                endpoint = new DPoint;
                endpoint->set
                (e1->pos());
            }
            // submit this line/bond to ChemData
	    evt = new XDC_Event(EVT_ADD_BOND_DASH);
	    evt->setStart(startpoint);
	    evt->setEnd(endpoint);
	    evt->setParam1(thick);
	    evt->setColor(currentColor);
	    emit XDCEventSignal(evt);
            //c->addBond(startpoint, endpoint, thick, 99, currentColor);
        }
        startpoint = NULL;
        endpoint = NULL;
        mode = MODE_DRAWLINE_DASH;
        repaint(false);
        return;
    }

    // MODE_DRAWLINE_UP_DRAWING (drawing line), and left button.
    // Finish line
    if ( (mode == MODE_DRAWLINE_UP_DRAWING) && (!mouse1down) ) {
        if (moved) {
            if (endpoint == NULL) {
                endpoint = new DPoint;
                endpoint->set
                (e1->pos());
            }
            // submit this line/bond to ChemData
	    evt = new XDC_Event(EVT_ADD_BOND_UP);
	    evt->setStart(startpoint);
	    evt->setEnd(endpoint);
	    evt->setColor(currentColor);
	    emit XDCEventSignal(evt);
            //c->addBond(startpoint, endpoint, 1, 5, currentColor);
        }
        startpoint = NULL;
        endpoint = NULL;
        mode = MODE_DRAWLINE_UP;
        repaint(false);
        return;
    }

    // MODE_DRAWLINE_DOWN_DRAWING (drawing line), and left button.
    // Finish line
    if ( (mode == MODE_DRAWLINE_DOWN_DRAWING) && (!mouse1down) ) {
        if (moved) {
            if (endpoint == NULL) {
                endpoint = new DPoint;
                endpoint->set
                (e1->pos());
            }
            // submit this line/bond to ChemData
	    evt = new XDC_Event(EVT_ADD_BOND_DOWN);
	    evt->setStart(startpoint);
	    evt->setEnd(endpoint);
	    evt->setColor(currentColor);
	    emit XDCEventSignal(evt);
            //c->addBond(startpoint, endpoint, 1, 7, currentColor);
        }
        startpoint = NULL;
        endpoint = NULL;
        mode = MODE_DRAWLINE_DOWN;
        repaint(false);
        return;
    }

    // MODE_DRAWARROW_DRAWING (drawing arrow), and left button.
    // Finish arrow
    if ( (mode == MODE_DRAWARROW_DRAWING) && (!mouse1down) ) {
        if (moved) {
            if (endpoint == NULL) {
                endpoint = new DPoint;
                endpoint->set
                (e1->pos());
            }
            // submit this arrow to ChemData
	    evt = new XDC_Event(EVT_ADD_ARROW);
	    evt->setStart(startpoint);
	    evt->setEnd(endpoint);
	    evt->setColor(currentColor);
	    evt->setParam1(bracket_type);
	    emit XDCEventSignal(evt);
            //c->addArrow(startpoint, endpoint, currentColor, bracket_type);
        }
        startpoint = NULL;
        endpoint = NULL;
        mode = MODE_DRAWARROW;
        repaint(false);
    }

    // MODE_DRAWCURVEARROW_DRAWING (drawing curved arrow), and left button.
    // Finish arrow
    if ( (mode == MODE_DRAWCURVEARROW_DRAWING) && (!mouse1down) ) {
        endpoint = new DPoint;
        endpoint->set
        (e1->pos());
	// submit this arrow to ChemData
	evt = new XDC_Event(EVT_ADD_CURVEARROW);
	evt->setStart(startpoint);
	evt->setEnd(endpoint);
	evt->setColor(currentColor);
	evt->setText(symbolfile);
	emit XDCEventSignal(evt);
        //c->addCurveArrow(startpoint, endpoint, currentColor, symbolfile);
        startpoint = NULL;
        endpoint = NULL;
        mode = MODE_DRAWCURVEARROW;
        repaint(false);
    }

    // MODE_DRAWBRACKET_DRAWING (drawing bracket), and left button.
    // Finish arrow
    if ( (mode == MODE_DRAWBRACKET_DRAWING) && (!mouse1down) ) {
        if (endpoint == NULL) {
            endpoint = new DPoint;
            endpoint->set
            (e1->pos());
        }
        // submit this bracket to ChemData
	evt = new XDC_Event(EVT_ADD_BRACKET);
	evt->setStart(startpoint);
	evt->setEnd(endpoint);
	evt->setColor(currentColor);
	evt->setParam1(bracket_type);
	emit XDCEventSignal(evt);
        //c->addBracket(startpoint, endpoint, currentColor, bracket_type);
        startpoint = NULL;
        endpoint = NULL;
        mode = MODE_DRAWBRACKET;
        repaint(false);
    }

    // MODE_SYMBOL: create Symbol
    if ( (mode == MODE_SYMBOL) && (!mouse1down) ) {
        endpoint = new DPoint;
        endpoint->set
        (e1->pos());
        if (highlightpoint != 0) {
            c->addSymbol(highlightpoint, symbolfile);  // add to existing point
        } else {
            c->addSymbol(endpoint, symbolfile);  // add at current mouse position
        }
        endpoint = NULL;
        repaint(false);
    }

    // MODE_RING: place ring
    if ( (mode == MODE_RING) && (!mouse1down) ) {
        endpoint = new DPoint;
        endpoint->set
        (e1->pos());
        // are we smart-placing this ring?
        if ( (smartplace != 0) && (highlightpoint != 0) ) {
            cout << "smart placement!" << endl;
            if (smartplace == 1)
                c->SmartPlace(symbolfile, highlightpoint);
            if (smartplace == 2)
                c->SmartPlaceToo(symbolfile, highlightpoint);
            if (smartplace == 3)
                c->SmartPlaceThree(symbolfile, highlightpoint);
            // Clear highlighted point
            highlightpoint = 0;
            endpoint = NULL;
            mode = MODE_SELECT_MULTIPLE_SELECTED;
            emit SignalSetStatusBar( tr("Select mode: left click on object to move") );
            setCursor(sizeAllCursor);
            selectionBox = c->selectionBox();
            repaint(false);
            smartplace = 0;
            return;
        }
        // translate ring to click point
        c->load(symbolfile);
        mode = MODE_SELECT_MULTIPLE_SELECTED;
        emit SignalSetStatusBar( tr("Select mode: left click on object to move, right click on object to edit") );
        setCursor(sizeAllCursor);
        selectionBox = c->selectionBox();
        double dx = endpoint->x - selectionBox.center().x();
        double dy = endpoint->y - selectionBox.center().y();
        //cout << "Move by " << dx << "," << dy << endl;
        c->Move(dx, dy);
        selectionBox.moveBy((int)dx, (int)dy);

        endpoint = NULL;
        repaint(false);
        smartplace = 0;
        return;
    }
}

void Render2D::mouseMoveEvent(QMouseEvent *e1) {
    if ( (mode == MODE_RING) && mouse1down )
        return;

    moved = true;

    DPoint tmp_pt(e1->x(), e1->y()); 
    Molecule *tmp_mol;

    // Tools
    if (mode == MODE_TOOL_CALCMW) {
        // check if we're over a molecule
        tmp_mol = c->insideMolecule(&tmp_pt);
        if (tmp_mol != 0) {
            Text *tmp_txt = tmp_mol->CalcMW();
            emit SignalSetStatusBar( tmp_txt->getText() +
                                     tr(", click to paste into drawing") );
            delete tmp_txt;
        } else {
            emit SignalSetStatusBar( tr("Click on a molecule to calculate its molecular weight") );
        }
        return;
    }
    if (mode == MODE_TOOL_CALCEF) {
      // check if we're over a molecule
      tmp_mol = c->insideMolecule(&tmp_pt);  // doesn't copy pointer
      if (tmp_mol != 0) {
            Text *tmp_txt = tmp_mol->CalcEmpiricalFormula();
            emit SignalSetStatusBar( tmp_txt->getText() +
                                     tr(", click to paste into drawing") );
            delete tmp_txt;
        } else {
            emit SignalSetStatusBar( tr("Click on a molecule to calculate its empirical formula") );
        }
        return;
    }

    // Dragging
    if (dragging && mouse3down) {
        cout << "Start drag" << endl;
        // make pixmap of selection
        QRect savebox = selectionBox;
        int prevmode = mode;
        mode = MODE_SELECT;
        c->DeselectAll();
        //repaint(false);
        QPixmap pm( savebox.size() );
        bitBlt( &pm, 0, 0, this, savebox.left(), savebox.top(),
                savebox.width(), savebox.height() );
        c->NewSelectRect(savebox, false);
        selectionBox = c->selectionBox();
        mode = prevmode;
        drag1 = new QImageDrag( pm.convertToImage(), this );
        drag1->dragCopy();
        dragging = false;
        repaint(false);
        setCursor(arrowCursor);
        mouse3down = false;
        return;
    }

    // MODE_TEXT: call special function to handle text events
    if (mode == MODE_TEXT) {
        DrawText_mouseMoveEvent(e1);
	if (prevpos == 0) { 
	  prevpos = new DPoint;
	}
        prevpos->x = e1->x();
        prevpos->y = e1->y();
        return;
    }
    // MODE_SELECT: call special function to handle select events
    if (mode < 199) {
        Select_mouseMoveEvent(e1);
	if (prevpos == 0) { 
	  prevpos = new DPoint;
	}
	prevpos->x = e1->x();
	prevpos->y = e1->y();
        return;
    }

    // MODE_TOOL_*: return
    if ((mode >= 600) && (mode < 699))
        return;

    //bool update;
    double ang, len;
    QString sang, slen;
    DPoint *prevhighlight = highlightpoint;
    Drawable *prevhighlightobject = highlightobject;
    // Create DPoint of current pointer position
    DPoint *e = new DPoint;
    DPoint *np = 0;
    e->x = e1->x();
    e->y = e1->y();
    double dist, distobj;
    // Get DPoint of nearest point
    np = c->FindNearestPoint(e, dist);
    // get Drawable of nearest object
    Drawable *no = c->FindNearestObject(e, distobj);

    // no buttons down
    if ( (mouse1down == false) && (mouse3down == false) ) {
        if (mode == MODE_DRAWARROW)
            return;

        // if (no != 0) {
        // highlight object if object close enough
        if ( (no != 0) && (mode == MODE_ERASE) && (distobj < 6.0) ) {
            highlightobject = no;
            if (prevhighlightobject != 0)
                prevhighlightobject->Highlight(false);
            highlightobject->Highlight(true);
            if (prevhighlightobject != highlightobject)
                repaint(false);
        }
        // unhighlight object if no object close
        if ( (mode == MODE_ERASE) && (no == 0 || distobj >= 6.0) ) {
            // Clear highlighted object
            highlightobject = 0;
            if (prevhighlightobject != 0)
                prevhighlightobject->Highlight(false);
            if (prevhighlightobject != highlightobject)
                repaint(false);
            return;
        }
        // highlight text object preferentially when MODE_SELECT...
        if ((no != 0) && (mode == MODE_SELECT) && (no->Type() == TYPE_TEXT) ) {
            highlightpoint = 0;
            highlightobject = no;
            if ( (prevhighlightobject != highlightobject) &&
                    (prevhighlightobject != 0) )
                prevhighlightobject->Highlight(false);
            highlightobject->Highlight(true);
            if (prevhighlightobject != highlightobject)
                repaint(false);
            // return since no need to check points
            return;
        }
        // highlight object if object close enough and no point close
        if ((no != 0) && (mode == MODE_SELECT) && (distobj < 6.0) && (dist >= 8.0) ) {
            highlightobject = no;
            if (prevhighlightobject != 0)
                prevhighlightobject->Highlight(false);
            highlightobject->Highlight(true);
            if (prevhighlightobject != highlightobject)
                repaint(false);
            // return since no need to check points
            return;
        }
        // unhighlight object if no object close
        if ( (mode == MODE_SELECT) && (no == 0 || distobj >= 6.0) ) {
            // Clear highlighted object
            highlightobject = 0;
            if (prevhighlightobject != 0)
                prevhighlightobject->Highlight(false);
            if (prevhighlightobject != highlightobject)
                repaint(false);
            // don't return; go on to check for points
        }
        // unhighlight object if point close
        if ( (mode == MODE_SELECT) && (dist < 8.0) ) {
            // Clear highlighted object
            highlightobject = 0;
            if (prevhighlightobject != 0)
                prevhighlightobject->Highlight(false);
            if (prevhighlightobject != highlightobject)
                repaint(false);
            // don't return; go on to check for points
        }
        // }
        if (np != 0) {
            //cout << dist << " to (" << np->x << "," << np->y << ")" << endl;
            if ( (mode == MODE_TEXT) && (dist < 8.0) ) {
                highlightpoint = np;
                if (prevhighlight != highlightpoint)
                    repaint(false);
                return;
            }
            if ( (mode == MODE_TEXT) && (dist >= 8.0) ) {
                // Clear highlighted point
                highlightpoint = 0;
                if (prevhighlight != highlightpoint)
                    repaint(false);
                return;
            }
            if ( (mode == MODE_SYMBOL) && (dist < 8.0) ) {
                highlightpoint = np;
                if (prevhighlight != highlightpoint)
                    repaint(false);
                return;
            }
            if ( (mode == MODE_SYMBOL) && (dist >= 8.0) ) {
                // Clear highlighted point
                highlightpoint = 0;
                if (prevhighlight != highlightpoint)
                    repaint(false);
                return;
            }
            if ( (mode == MODE_SELECT) && (dist < 8.0) ) {
                highlightpoint = np;
                if (prevhighlight != highlightpoint)
                    repaint(false);
                return;
            }
            if ( (mode == MODE_SELECT) && (dist >= 8.0) ) {
                // Clear highlighted point
                highlightpoint = 0;
                if (prevhighlight != highlightpoint)
                    repaint(false);
                return;
            }
            if ( (mode == MODE_DRAWLINE) && (dist < 6.0) ) {
                highlightpoint = np;
                if (prevhighlight != highlightpoint)
                    repaint(false);
                return;
            }
            if ( (mode == MODE_DRAWLINE) && (dist >= 6.0) ) {
                // Clear highlighted point
                highlightpoint = 0;
                if (prevhighlight != highlightpoint)
                    repaint(false);
                return;
            }
            if ( (mode == MODE_RING) && smartplace && (dist < 6.0) ) {
                highlightpoint = np;
                if (prevhighlight != highlightpoint)
                    repaint(false);
                return;
            }
            if ( (mode == MODE_RING) && smartplace && (dist >= 6.0) ) {
                // Clear highlighted point
                highlightpoint = 0;
                if (prevhighlight != highlightpoint)
                    repaint(false);
                return;
            }
            if ( (mode == MODE_DRAWLINE_DASH) && (dist < 6.0) ) {
                highlightpoint = np;
                if (prevhighlight != highlightpoint)
                    repaint(false);
                return;
            }
            if ( (mode == MODE_DRAWLINE_DASH) && (dist >= 6.0) ) {
                // Clear highlighted point
                highlightpoint = 0;
                if (prevhighlight != highlightpoint)
                    repaint(false);
                return;
            }
            if ( (mode == MODE_DRAWLINE_UP) && (dist < 6.0) ) {
                highlightpoint = np;
                if (prevhighlight != highlightpoint)
                    repaint(false);
                return;
            }
            if ( (mode == MODE_DRAWLINE_UP) && (dist >= 6.0) ) {
                // Clear highlighted point
                highlightpoint = 0;
                if (prevhighlight != highlightpoint)
                    repaint(false);
                return;
            }
            if ( (mode == MODE_DRAWLINE_DOWN) && (dist < 6.0) ) {
                highlightpoint = np;
                if (prevhighlight != highlightpoint)
                    repaint(false);
                return;
            }
            if ( (mode == MODE_DRAWLINE_DOWN) && (dist >= 6.0) ) {
                // Clear highlighted point
                highlightpoint = 0;
                if (prevhighlight != highlightpoint)
                    repaint(false);
                return;
            }
        }
        return; // rest of function only if mouse button down
    }

    // we're probably going to draw something...
    repaint(false);
    directdraw = true;

    // MODE_DRAWLINE_DRAWING: draw temporary line
    if ( (mode == MODE_DRAWLINE_DRAWING) && mouse1down ) {
        // if within range of existing point AND the end point is not the same
        // as the start point, snap to that point
        if ( (dist < 6.0) && (startpoint != np) ) {
            highlightpoint = np;
            endpoint = np;
        } else {
            endpoint = new DPoint;
            endpoint->x = e1->x();
            endpoint->y = e1->y();
            highlightpoint = 0;  // stop highlighting
            if (preferences.getBond_fixed()) { // fix endpoint if fixed set
                CorrectEndpoint_bond();
                np = c->FindNearestPoint(endpoint, dist);
                if (dist < 2.0) {
                    highlightpoint = np;
                    endpoint = np;
                }
            }
        }
        ang = Drawable::getAngle(startpoint, endpoint);
        len = startpoint->distanceTo(endpoint);
        sang.setNum(ang);
        slen.setNum(len);
        emit SignalSetStatusBar("Draw Line - Length = " + slen + ", Angle = " +
                                sang);
        drawLine( startpoint->toQPoint(), endpoint->toQPoint(), thick,
                  currentColor );
        directdraw = false;
        return;
    }

    // MODE_DRAWLINE_DASH_DRAWING: draw temporary line
    if ( (mode == MODE_DRAWLINE_DASH_DRAWING) && mouse1down ) {
        // if within range of existing point AND the end point is not the same
        // as the start point, snap to that point
        if ( (dist < 6.0) && (startpoint != np) ) {
            highlightpoint = np;
            endpoint = np;
        } else {
            endpoint = new DPoint;
            endpoint->x = e1->x();
            endpoint->y = e1->y();
            highlightpoint = 0;  // stop highlighting
            if (preferences.getBond_fixed()) { // fix endpoint if fixed set
                CorrectEndpoint_bond();
                np = c->FindNearestPoint(endpoint, dist);
                if (dist < 2.0) {
                    highlightpoint = np;
                    endpoint = np;
                }
            }
        }
        drawLine( startpoint->toQPoint(), endpoint->toQPoint(), 1,
                  currentColor, 1 );
        directdraw = false;
        return;
    }

    // MODE_DRAWLINE_UP_DRAWING: draw temporary line
    if ( (mode == MODE_DRAWLINE_UP_DRAWING) && mouse1down ) {
        // if within range of existing point AND the end point is not the same
        // as the start point, snap to that point
        if ( (dist < 6.0) && (startpoint != np) ) {
            highlightpoint = np;
            endpoint = np;
        } else {
            endpoint = new DPoint;
            endpoint->x = e1->x();
            endpoint->y = e1->y();
            highlightpoint = 0;  // stop highlighting
            if (preferences.getBond_fixed()) { // fix endpoint if fixed set
                CorrectEndpoint_bond();
                np = c->FindNearestPoint(endpoint, dist);
                if (dist < 2.0) {
                    highlightpoint = np;
                    endpoint = np;
                }
            }
        }
        drawUpLine( startpoint->toQPoint(), endpoint->toQPoint(), QColor(0,0,0) );
        directdraw = false;
        return;
    }

    // MODE_DRAWLINE_DOWN_DRAWING: draw temporary line
    if ( (mode == MODE_DRAWLINE_DOWN_DRAWING) && mouse1down ) {
        // if within range of existing point AND the end point is not the same
        // as the start point, snap to that point
        if ( (dist < 6.0) && (startpoint != np) ) {
            highlightpoint = np;
            endpoint = np;
        } else {
            endpoint = new DPoint;
            endpoint->x = e1->x();
            endpoint->y = e1->y();
            highlightpoint = 0;  // stop highlighting
            if (preferences.getBond_fixed()) { // fix endpoint if fixed set
                CorrectEndpoint_bond();
                np = c->FindNearestPoint(endpoint, dist);
                if (dist < 2.0) {
                    highlightpoint = np;
                    endpoint = np;
                }
            }
        }
        drawDownLine(startpoint->toQPoint(), endpoint->toQPoint(), QColor(0,0,0));
        directdraw = false;
        return;
    }

    // MODE_DRAWARROW_DRAWING: draw temporary line
    if ( (mode == MODE_DRAWARROW_DRAWING) && mouse1down ) {
        endpoint = new DPoint;
        endpoint->x = e1->x();
        endpoint->y = e1->y();
        if (preferences.getArrow_fixed()) { // fix endpoint if fixed set
            CorrectEndpoint_arrow();
        }
        drawArrow( startpoint->toQPoint(), endpoint->toQPoint(), QColor(0,0,0),
                   bracket_type );
        directdraw = false;
        return;
    }

    // MODE_DRAWARROW_DRAWING: draw temporary line
    if ( (mode == MODE_DRAWCURVEARROW_DRAWING) && mouse1down ) {
        endpoint = new DPoint;
        endpoint->x = e1->x();
        endpoint->y = e1->y();
        // should not draw curve arrows fixed, even if selected
        //if (fixed) { // fix endpoint if fixed set
        //  CorrectEndpoint();
        //}
        drawCurveArrow( startpoint->toQPoint(), endpoint->toQPoint(),
                        QColor(0,0,0), symbolfile );
        directdraw = false;
        return;
    }

    // MODE_DRAWBRACKET_DRAWING: draw temporary bracket
    if ( (mode == MODE_DRAWBRACKET_DRAWING) && mouse1down ) {
        endpoint = new DPoint;
        endpoint->x = e1->x();
        endpoint->y = e1->y();
        drawBracket( startpoint->toQPoint(), endpoint->toQPoint(), QColor(0,0,0),
                     bracket_type );
        directdraw = false;
        return;
    }
}

// handle resize event
void Render2D::resizeEvent(QResizeEvent *rz) {
    dbuffer.resize(renderWidth, renderHeight);
}

void Render2D::paintEvent(QPaintEvent *) {
    // draw background
    //drawFillBox(QPoint(0,0), QPoint(renderWidth, renderHeight), bgcolor);
    // clear buffer pixmap
    dbuffer.fill(bgcolor);
    // draw all data
    c->drawAll();
    // local/temporary draw operations
    if (highlightpoint != 0) {
        drawBox(QPoint(highlightpoint->x - 2, highlightpoint->y - 2),
                QPoint(highlightpoint->x + 2, highlightpoint->y + 2),
                QColor(0,0,0));
    }
    if ( (mode == MODE_TEXT) && (localtext != 0) )
        localtext->EditRender();
    // if multiple selection, draw rotate and resize handles
    if ( (mode > 120) && (mode < 129) ) {
        // draw selection box
        drawBox(selectionBox.topLeft(), selectionBox.bottomRight(),
                QColor(0,0,0));
        // draw rotate handle
        rotateHandle = selectionBox.topRight();
        drawFillBox( QPoint(rotateHandle.x() - 5, rotateHandle.y()),
                     QPoint(rotateHandle.x(), rotateHandle.y() + 5),
                     QColor(0,0,0) );
        // draw resize handle
        resizeHandle = selectionBox.bottomRight();
        drawFillBox( QPoint(resizeHandle.x() - 5, resizeHandle.y() - 5),
                     resizeHandle,
                     QColor(0,0,0) );
    }
    if (mode == 91) {
        // draw selection box
        drawBox(selectionBox.topLeft(), selectionBox.bottomRight(),
                QColor(0,0,0));
        // draw rotate handle
        rotateHandle = selectionBox.topRight();
        drawFillBox( QPoint(rotateHandle.x() - 5, rotateHandle.y()),
                     QPoint(rotateHandle.x(), rotateHandle.y() + 5),
                     QColor(0,0,0) );
        // draw resize handle
        resizeHandle = selectionBox.bottomRight();
        drawFillBox( QPoint(resizeHandle.x() - 5, resizeHandle.y() - 5),
                     resizeHandle,
                     QColor(0,0,0) );
    }
    // now bitBlt buffer onto widget
    bitBlt(this, 0, 0, &dbuffer);
}
