+//
+// GUEmap
+// (C) 1997-2007 Christopher J. Madsen
+// (C) 2019 James Hammons
+//
+// GUEmap is licensed under either version 2 of the GPL, or (at your option)
+// any later version. See LICENSE file for details.
+//
+// mapview.cpp: implementation of the CMapView class
+//
+
+#include "mapview.h"
+
+#include <math.h>
+#include "mainwin.h"
+#include "mapdialog.h"
+#include "mapdoc.h"
+#include "mathconstants.h"
+//#include "properties.h"
+#include "roomdialog.h"
+#include "undo.h"
+
+
+const int
+ penEdgeWidth = 9,
+ penPageWidth = 20,
+ penRoomWidth = 5,
+ maxZoom = 200,
+ minZoom = 20,
+ minZoomGrid = 50;
+
+const unsigned int
+ clickTicks = 500,
+ menuTimer = 1;
+
+struct DirectionName
+{
+ RoomCorner dir;
+ const char * name;
+};
+
+static const DirectionName directions[] = {
+ { rcN, "n" }, { rcS, "s" }, { rcE, "e" }, { rcW, "w" },
+ { rcNE, "ne" }, { rcNW, "nw" }, { rcSE, "se" }, { rcSW, "sw" },
+ { rcNNE, "nne" }, { rcNNW, "nnw" }, { rcSSE, "sse" }, { rcSSW, "ssw" },
+ { rcUp, "u" }, { rcDown, "d" }, { rcIn, "i" }, { rcOut, "o" },
+ { rcN, "north" }, { rcS, "south" }, { rcE, "east" }, { rcW, "west" },
+ { rcNE, "northeast" }, { rcNW, "northwest" },
+ { rcSE, "southeast" }, { rcSW, "southwest" },
+ { rcUp, "up" }, { rcDown, "down" }, { rcIn, "in" }, { rcOut, "out" },
+ { rcNone, NULL }
+};
+
+static const char a2z[] = "abcdefghijklmnopqrstuvwxyz";
+
+
+//
+// Parse a direction word:
+//
+// Input:
+// text: The string to be tested (must be in lowercase, may be empty)
+//
+// Output:
+// text: Has the direction word and whitespace stripped from the beginning
+//
+// Returns:
+// The direction indicated by the text
+// rcNone if not a direction
+//
+RoomCorner parseDirection(string & text)
+{
+#if 0
+ const CString word(text.SpanIncluding(a2z));
+
+ if (!word.IsEmpty())
+ {
+ for(int i=0; directions[i].dir != rcNone; i++)
+ {
+ if (word == directions[i].name)
+ {
+ text = text.Mid(word.GetLength());
+ text.TrimLeft();
+ return directions[i].dir;
+ }
+ }
+ }
+#endif
+
+ return rcNone;
+}
+
+
+#if 0
+/////////////////////////////////////////////////////////////////////////////
+// CRepaginateDlg dialog
+
+class CRepaginateDlg : public CDialog
+{
+ // Construction
+ public:
+ CRepaginateDlg(); // standard constructor
+
+ // Dialog Data
+ //{{AFX_DATA(CRepaginateDlg)
+ enum { IDD = IDD_REPAGINATE };
+ //}}AFX_DATA
+
+ // Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CRepaginateDlg)
+ //}}AFX_VIRTUAL
+
+ // Implementation
+ protected:
+ // Generated message map functions
+ //{{AFX_MSG(CRepaginateDlg)
+ afx_msg void OnYes();
+ virtual bool OnInitDialog();
+ //}}AFX_MSG
+
+ DECLARE_MESSAGE_MAP();
+};
+#endif
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+// CMapView
+
+#if 0
+IMPLEMENT_DYNCREATE(CMapView, CScrollZoomView)
+
+BEGIN_MESSAGE_MAP(CMapView, CScrollZoomView)
+ //{{AFX_MSG_MAP(CMapView)
+ ON_COMMAND(ID_EDIT_ADD_CORNER, OnEditAddCorner)
+ ON_COMMAND(ID_EDIT_ADD_PAGE, OnEditAddPage)
+ ON_COMMAND(ID_EDIT_ADD_ROOM, OnEditAddRoom)
+ ON_COMMAND(ID_EDIT_CLEAR, OnEditClear)
+ ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
+ ON_COMMAND(ID_EDIT_CUT, OnEditCut)
+ ON_COMMAND(ID_EDIT_PAGINATE, OnEditPaginate)
+ ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
+ ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
+ ON_COMMAND(ID_EDIT_SELECT_CONNECTED, OnEditSelectConnected)
+ ON_COMMAND(ID_VIEW_GRID, OnViewGrid)
+ ON_COMMAND(ID_WINDOW_REFRESH, OnWindowRefresh)
+ ON_UPDATE_COMMAND_UI(ID_EDIT_ADD_CORNER, OnUpdateEditAddCorner)
+ ON_UPDATE_COMMAND_UI(ID_EDIT_CLEAR, OnUpdateSelectedUnlocked)
+ ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateSelectedUnlocked)
+ ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateSelectedUnlocked)
+ ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateEditPaste)
+ ON_UPDATE_COMMAND_UI(ID_EDIT_SELECT_ALL, OnUpdateUnlocked)
+ ON_UPDATE_COMMAND_UI(ID_EDIT_SELECT_CONNECTED, OnUpdateSelectedUnlocked)
+ ON_UPDATE_COMMAND_UI(ID_VIEW_GRID, OnUpdateViewGrid)
+ ON_WM_CHAR()
+ ON_WM_KEYDOWN()
+ ON_WM_LBUTTONDBLCLK()
+ ON_WM_LBUTTONDOWN()
+ ON_WM_LBUTTONUP()
+ ON_WM_MOUSEMOVE()
+ ON_WM_MOUSEWHEEL()
+ ON_WM_RBUTTONDOWN()
+ ON_WM_RBUTTONUP()
+ ON_WM_SIZE()
+ ON_WMtrIMER()
+ //}}AFX_MSG_MAP
+ ON_WM_MOUSEACTIVATE()
+ ON_BN_CLICKED(IDC_NAV_GO, OnNavGo)
+ ON_COMMAND_RANGE(ID_EDIT_PROPERTIES, ID_EDIT_MAP_PROPERTIES, OnEditProperties)
+ ON_COMMAND_RANGE(ID_NAV_GO_NORTH, ID_NAV_STUB2_OUT, OnNavGoDir)
+ ON_COMMAND_RANGE(ID_VIEW_ZOOM_IN, ID_VIEW_ZOOM_OUT, OnViewZoom)
+ ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_ZOOM_IN, ID_VIEW_ZOOM_OUT, OnUpdateViewZoom)
+ // Standard printing commands
+ ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
+ ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
+ ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
+END_MESSAGE_MAP();
+#endif
+
+//===========================================================================
+// Class CMapView:
+//
+// Member Variables:
+// opInProgress: Indicates what's happening while the mouse button is down
+// gmoAddCorner:
+// iTmp: The edge that needs a corner
+// gmoAddEdge:
+// bTmp: The modification state of the document
+// edgeTmp: The edge being created
+// e2Tmp: The original edge data (if iTmp >= 0)
+// iTmp: -1 if this is a new edge, >=0 if changing an old edge
+// p1Tmp: The start point (fixed) of the rubber band cursor
+// p2Tmp: The end point (moving) of the rubber band cursor
+// gmoChangeEdge:
+// bTmp: The modification state of the document
+// edgeTmp: Info about the other end of this edge
+// iTmp: The edge number about to be changed
+// p1Tmp, p2Tmp: The start point (fixed) of the rubber band cursor
+// gmoDeleting:
+// Used in OnEditClear to tell OnUpdate not to clear the selection
+// gmoSelectBox:
+// p1Tmp: The fixed corner of the selection rectangle
+// p2Tmp: The moving corner of the selection rectangle
+// rTmp: The current selection rectangle
+// gmoControlDown:
+// bTmp: TRUE if the room or page was already selected
+// b2Tmp: True if this is a page instead of a room
+// iTmp: The room number where the button was pressed (if bTmp==TRUE)
+// p1Tmp: The grid cell where the mouse button was pressed
+// p2Tmp: The offset to the current grid cell (in logical coordinates)
+// gmoShiftDown:
+// iTmp: The number of the selected page (-1 if a room)
+// p1Tmp: The grid cell where the mouse button was pressed
+// p2Tmp: The position of the selected room
+// gmoDrag: (all dragging operations)
+// p2Tmp:
+// The offset to the current grid cell (in logical coordinates)
+// rTmp:
+// A rectangle enclosing the original position of all rooms being
+// dragged. Used to ensure we don't push a room off the edge.
+// font:
+// The font used for room names
+// numSelected:
+// The number of rooms currently selected
+// numSelectedPages:
+// The number of pages currently selected
+// printingPage:
+// The number of the page being printed or previewed
+// 0 means normal screen display
+// scrollDrag:
+// True if we are in the middle of a scroll-by-drag operation
+// scrollDragStart:
+// The point under the cursor when a scrollDrag started
+// selectedOne:
+// The selected room's number, if exactly 1 room is selected
+// -1 otherwise
+// selected:
+// selected[N] is non-zero iff room N is selected
+// 2 means the room should stay selected during gmoSelectBox
+// selectedPage:
+// selectedPage[N] is non-zero iff page N is selected
+// 2 means the page should stay selected during gmoSelectBox
+// zoom:
+// Zoom factor in percent
+//
+
+//
+// CMapView construction/destruction
+//
+MapView::MapView(QWidget * parent/*= NULL*/): QWidget(parent),
+ opInProgress(gmoNone), hoveredEdge(-1), printingPage(0), scrollDrag(false),
+ scrollDragTimer(0), font("Arial", 24), showCorners(false), showGrid(true),
+// showPages(false), zoom(100), shiftDown(false), ctrlDown(false),
+ showPages(false), zoom(20.0), shiftDown(false), ctrlDown(false),
+ altDown(false), mouseDown(false), offset(0, 0)
+{
+ doc = new MapDoc();
+
+ selectedPage.resize(doc->page.size(), 0);
+ clearSelection(false);
+
+ setFocusPolicy(Qt::StrongFocus);
+ // Make sure we get *ALL* mouse move events!
+ setMouseTracking(true);
+
+ // Set the document size:
+//scrollzoom.cpp -> init(4 * gridX, doc->getDocSize(), QSize(gridX, gridY));
+// CClientDC dc(this);
+// OnPrepareDC(&dc);
+// LOGFONT lf;
+// memset(&lf, 0, sizeof(lf));
+// lf.lfHeight = 62;
+// strcpy(lf.lfFaceName, "Arial");
+// font.CreateFontIndirect(&lf);
+
+// if (doc->locked)
+// OnUpdate(NULL, dupNavigationMode, NULL);
+
+// CScrollZoomView::OnInitialUpdate();
+// setScrollBars(); // Now fix the scroll bars
+
+ // Actions
+ deleteRoomAct = CreateAction("Delete", "Delete room", "Deletes selected rooms", QIcon(), QKeySequence(), false, this);
+ connect(deleteRoomAct, SIGNAL(triggered()), this, SLOT(HandleDelete()));
+
+ roomPropertiesAct = CreateAction("Properties...", "Properties", "Opens the properties dialog for this room", QIcon(), QKeySequence(), false, this);
+ connect(roomPropertiesAct, SIGNAL(triggered()), this, SLOT(HandleRoomProperties()));
+
+ mapPropertiesAct = CreateAction("Properties...", "Properties", "Opens the properties dialog for this map", QIcon(), QKeySequence(), false, this);
+ connect(mapPropertiesAct, SIGNAL(triggered()), this, SLOT(HandleMapProperties()));
+
+ selectConnectedAct = CreateAction("Select connected rooms", "Select connected", "Selects connected rooms", QIcon(), QKeySequence(), false, this);
+
+ addCornerAct = CreateAction("Add corner", "Add corner", "Adds a corner to the selected room", QIcon(), QKeySequence(), false, this);
+ connect(addCornerAct, SIGNAL(triggered()), this, SLOT(HandleAddCorner()));
+
+ addRoomAct = CreateAction("Add room", "Add room", "Adds a rom to the map", QIcon(), QKeySequence(), false, this);
+ connect(addRoomAct, SIGNAL(triggered()), this, SLOT(HandleAddRoom()));
+
+ addPageAct = CreateAction("Add Page", "Add Page", "Adds a page to the map", QIcon(), QKeySequence(), false, this);
+
+ addUnexploredAct = CreateAction("Unexplored", "Unexplored", "Adds an unexplored notation to the selected corner", QIcon(), QKeySequence(), false, this);
+ connect(addUnexploredAct, SIGNAL(triggered()), this, SLOT(HandleAddUnexplored()));
+
+ addLoopBackAct = CreateAction("Loop back", "Loop back", "Adds a loop back notation to the selected corner", QIcon(), QKeySequence(), false, this);
+ connect(addLoopBackAct, SIGNAL(triggered()), this, SLOT(HandleAddLoopBack()));
+
+ addNoExitAct = CreateAction("No Exit", "No Exit", "Adds a no exit notation to the selected corner", QIcon(), QKeySequence(), false, this);
+ connect(addNoExitAct, SIGNAL(triggered()), this, SLOT(HandleAddNoExit()));
+
+ addUpAct = CreateAction("Up", "Up", "Marks the selected corner as Up", QIcon(), QKeySequence(), false, this);
+ connect(addUpAct, SIGNAL(triggered()), this, SLOT(HandleAddUp()));
+
+ addDownAct = CreateAction("Down", "Down", "Marks the selected corner as Down", QIcon(), QKeySequence(), false, this);
+ connect(addDownAct, SIGNAL(triggered()), this, SLOT(HandleAddDown()));
+
+ addInAct = CreateAction("In", "In", "Marks the selected corner as In", QIcon(), QKeySequence(), false, this);
+ connect(addInAct, SIGNAL(triggered()), this, SLOT(HandleAddIn()));
+
+ addOutAct = CreateAction("Out", "Out", "Marks the selected corner as Out", QIcon(), QKeySequence(), false, this);
+ connect(addOutAct, SIGNAL(triggered()), this, SLOT(HandleAddOut()));
+
+ addOneWayAct = CreateAction("One Way", "One Way", "Marks the selected corner as one way exit", QIcon(), QKeySequence(), false, this);
+ connect(addOneWayAct, SIGNAL(triggered()), this, SLOT(HandleAddOneWay()));
+
+ clearOneWayAct = CreateAction("Two Way", "Two Way", "Marks the selected corner as traversable both ways", QIcon(), QKeySequence(), false, this);
+ connect(clearOneWayAct, SIGNAL(triggered()), this, SLOT(HandleClearOneWay()));
+
+ addRestrictedAct = CreateAction("Restricted", "Restricted", "Marks the selected corner as a restricted exit", QIcon(), QKeySequence(), false, this);
+ connect(addRestrictedAct, SIGNAL(triggered()), this, SLOT(HandleAddRestricted()));
+
+ clearRestrictedAct = CreateAction("Unrestricted", "Unrestricted", "Marks the selected corner as an unrestricted exit", QIcon(), QKeySequence(), false, this);
+ connect(clearRestrictedAct, SIGNAL(triggered()), this, SLOT(HandleClearRestricted()));
+
+ // Popup menus
+ roomContextMenu = new QMenu(this);
+ mapContextMenu = new QMenu(this);
+
+ roomContextMenu->addAction(deleteRoomAct);
+ roomContextMenu->addAction(roomPropertiesAct);
+ roomContextMenu->addAction(selectConnectedAct);
+ roomContextMenu->addAction(addCornerAct);
+ QMenu * sub = roomContextMenu->addMenu(tr("Edge"));
+ sub->addAction(addLoopBackAct);
+ sub->addAction(addUnexploredAct);
+ sub->addAction(addNoExitAct);
+ sub->addAction(addUpAct);
+ sub->addAction(addDownAct);
+ sub->addAction(addInAct);
+ sub->addAction(addOutAct);
+ sub->addAction(addOneWayAct);
+ sub->addAction(clearOneWayAct);
+ sub->addAction(addRestrictedAct);
+ sub->addAction(clearRestrictedAct);
+
+ mapContextMenu->addAction(mapPropertiesAct);
+ mapContextMenu->addAction(addRoomAct);
+ mapContextMenu->addAction(addPageAct);
+ mapContextMenu->addAction(deleteRoomAct);
+}
+
+
+MapView::~MapView()
+{
+ delete doc;
+// gueApp()->closingView(this); // Remove any comment for this view
+}
+
+
+void MapView::DrawArrowhead(QPainter * painter, QPointF head, QPointF tail)
+{
+ QPolygonF arrow;
+
+ const double angle = Angle(tail - head);
+ const double orthoAngle = angle + QTR_TAU;
+ const double size = 5.0;
+
+ QPointF ortho(cos(orthoAngle), sin(orthoAngle));
+ QPointF unit = UnitVector(head - tail);
+
+ QPointF p1 = head - (unit * 9.0 * size);
+ QPointF p2 = p1 + (ortho * 3.0 * size);
+ QPointF p3 = p1 - (ortho * 3.0 * size);
+
+ arrow << head << p2 << p3;
+ painter->drawPolygon(arrow);
+}
+
+
+void MapView::DrawNoExit(QPainter * painter, QPointF head, QPointF tail)
+{
+ const double angle = Angle(tail - head);
+ const double orthoAngle = angle + QTR_TAU;
+ const double size = 5.0;
+
+ QPointF ortho(cos(orthoAngle), sin(orthoAngle));
+ QPointF unit = UnitVector(head - tail);
+
+ QPointF p2 = head + (ortho * 3.0 * size);
+ QPointF p3 = head - (ortho * 3.0 * size);
+
+ painter->drawLine(p2, p3);
+}
+
+
+//
+// MapView drawing
+//
+void MapView::paintEvent(QPaintEvent * /*event*/)
+{
+ const char edgeLabel[] = "UDIO";
+
+ const QPoint edgLblOffset[] = {
+ // N, S, E, W
+ { roomWidth / 2 + 24, -13 }, { roomWidth / 2 - 48, roomHeight + 52 },
+ { roomWidth + 24, roomHeight / 2 + 57 }, { -48, roomHeight / 2 - 19 },
+ // NE, NW, SE, SW
+ { roomWidth - 48, -13 }, { 24, -13 },
+ { roomWidth - 48, roomHeight + 52 }, { 24, roomHeight + 52 },
+ // NNE, NNW, SSE, SSW
+ { 3 * roomWidth / 4 + 24, -13 }, { roomWidth / 4 + 24, -13 },
+ { 3 * roomWidth / 4 - 48, roomHeight + 52 },
+ { roomWidth / 4 - 48, roomHeight + 52 }
+ };
+
+ const int
+ cantGoSide = 19,
+ cantGoAngleX = gridY / 6,
+ cantGoAngleY = gridX / 6;
+/*
+ rcN, rcS, rcE, rcW,
+ rcNE, rcNW, rcSE, rcSW,
+ rcNNE, rcNNW, rcSSE, rcSSW,
+*/
+ QRect cornerRect[] = {
+ { roomWidth * 5 / 16, 0, roomWidth * 6 / 16, roomHeight / 4 },
+ { roomWidth * 5 / 16, roomHeight * 3 / 4, roomWidth * 6 / 16, roomHeight / 4 },
+ { roomWidth * 3 / 4, roomHeight / 4, roomWidth / 4, roomHeight / 2 },
+ { 0, roomHeight / 4, roomWidth / 4, roomHeight / 2 },
+ { roomWidth * 13 / 16, 0, roomWidth * 3 / 16, roomHeight / 4 },
+ { 0, 0, roomWidth * 3 / 16, roomHeight / 4 },
+ { roomWidth * 13 / 16, roomHeight * 3 / 4, roomWidth * 3 / 16, roomHeight / 4 },
+ { 0, roomHeight * 3 / 4, roomWidth * 3 / 16, roomHeight / 4 },
+ { roomWidth * 11 / 16, 0, roomWidth * 2 / 16, roomHeight / 4 },
+ { roomWidth * 3 / 16, 0, roomWidth * 2 / 16, roomHeight / 4 },
+ { roomWidth * 11 / 16, roomHeight * 3 / 4, roomWidth * 2 / 16, roomHeight / 4 },
+ { roomWidth * 3 / 16, roomHeight * 3 / 4, roomWidth * 2 / 16, roomHeight / 4 },
+ };
+
+ QPainter painter(this);
+ QPainter * dc = &painter;
+
+ painter.setRenderHint(QPainter::Antialiasing);
+
+#if 0
+ dc->save();
+ dc->setFont(font);
+ dc->setPen(QColor(0xFF, 0x7F, 0x00));
+// dc->drawText(20, 50, QString("<%1, %2>").arg(mouse.x()).arg(mouse.y()));
+ dc->drawText(20, 50, QString("<%1, %2>, %3").arg(mouse.x()).arg(mouse.y()).arg(hoveredEdge));
+ dc->restore();
+#endif
+
+ QTransform t1;
+ t1.scale(zoom / 100.0, zoom / 100.0);
+// t1.scale(+0.20, +0.20);
+// t1.scale(+0.40, +0.40);
+ t1.translate(offset.x(), offset.y());
+ painter.setTransform(t1);
+#if 0
+// QPainter painter(this);
+ painter.save();
+ painter.setPen(QPen(Qt::blue, 1, Qt::DashLine));
+ painter.drawRect(0, 0, 100, 100);
+
+ QTransform transform;
+ transform.translate(50, 50);
+ transform.rotate(45);
+ transform.scale(0.5, -1.0);
+ painter.setTransform(transform);
+
+ painter.setFont(QFont("Helvetica", 24));
+ painter.setPen(QPen(Qt::black, 1));
+ painter.drawText(20, 10, "QTransform");
+ painter.restore();
+#endif
+
+#if 0
+ QBrush focusBrush;
+ QPen penEdge;
+ QPen penGrid;
+ QPen penRoom;
+ LOGBRUSH lb;
+ lb.lbStyle = BS_SOLID;
+ lb.lbColor = RGB(0, 0, 0);
+
+ if (!focusBrush.CreateHatchBrush(HS_BDIAGONAL, PALETTERGB(128, 128, 128))
+ || !penEdge.CreatePen(PS_GEOMETRIC | PS_ENDCAP_FLAT, penEdgeWidth, &lb)
+ || !penGrid.CreatePen(PS_DOT, 0, RGB(0, 0, 0))
+ || !penRoom.CreatePen(PS_SOLID, penRoomWidth, RGB(0, 0, 0)))
+ return;
+
+ QBrush * const whiteBrush = dc->GetCurrentBrush();
+ QPen * const oldPen = dc->GetCurrentPen();
+ QFont * const oldFont = dc->SelectObject(&font);
+ const unsigned int oldAlign = dc->SetTextAlign(TA_CENTER | TA_BASELINE | TA_NOUPDATECP);
+#else
+ QBrush focusBrush(QColor(0xC0, 0xC0, 0xC0), Qt::BDiagPattern);
+ QPen penEdge(QColor(0, 0, 0), penEdgeWidth);
+ QPen penEdgeDashed(QColor(0, 0, 0), penEdgeWidth, Qt::DashLine);
+ QPen penEdgeHover(QColor(0xFF, 0, 0), penEdgeWidth);
+ QPen penEdgeDashedHover(QColor(0xFF, 0, 0), penEdgeWidth, Qt::DashLine);
+ QPen penGrid(QColor(0, 0, 0), 1, Qt::DotLine);
+ QPen penRoom(QColor(0, 0, 0), 1);
+ dc->setFont(font);
+#endif
+
+ if (printingPage)
+ {
+ // Clipping in OnPrepareDC screws up print preview
+ QRect r = doc->getPageRect(printingPage - 1);
+/// dc->SetWindowOrg(r.left(), r.bottom()); // FIXME adjust for margins
+/// dc->IntersectClipRect(&r);
+// dc->setTransform(QTransform::translate(r.left(), r.bottom()));
+ }
+
+#if 0
+ // Draw the page outlines:
+ if ((showPages || numSelectedPages) && !dc->IsPrinting())
+ {
+ dc->SetBkMode(TRANSPARENT);
+ QPen penPage;
+ lb.lbColor = RGB(192, 192, 192);
+ VERIFY(penPage.CreatePen(PS_GEOMETRIC | PS_ENDCAP_FLAT, penPageWidth, &lb));
+ dc->SelectObject(&penPage);
+ const PageVec & pageVec = doc->page;
+ TCHAR pageNum[4];
+ int pNum = 1;
+ dc->SelectStockObject(NULL_BRUSH);
+ QBrush * const nullBrush = dc->GetCurrentBrush();
+ bool focused = false;
+
+ for(PageConstItr p=pageVec.begin(); p!=pageVec.end(); ++p, ++pNum)
+ {
+ doc->getPageRect(*p, r);
+
+ if (dc->RectVisible(r))
+ {
+ const bool selectedI = selectedPage[pNum - 1] != 0;
+
+ if (!selectedI && !showPages)
+ continue; // Only show selected pages
+
+ if (selectedI != focused)
+ {
+ focused = selectedI;
+ dc->SelectObject(focused ? &focusBrush : nullBrush);
+ }
+/// CRgn inside,outside;
+/// VERIFY(outside.CreateRectRgnIndirect(&r));
+/// VERIFY(inside.CreateRectRgn(r.left + gridX, r.bottom - gridY,
+/// r.right - gridX, r.top + gridY));
+/// outside.CombineRgn(&outside, &inside, RGN_DIFF);
+/// dc->FillRgn(&outside, &focusBrush);
+
+ dc->Rectangle(r.left + penPageWidth / 4, r.bottom - penPageWidth / 4, r.right, r.top);
+ ASSERT(pNum < 1000);
+ _itot(pNum, pageNum, 10);
+ const int pageNumL = strlen(pageNum);
+
+ for(i=r.left+3*gridX/2; i<r.right-gridX; i+=gridX)
+ {
+ dc->TextOut(i, r.bottom - gridY * 7 / 8, pageNum, pageNumL);
+ dc->TextOut(i, r.top + gridY / 4, pageNum, pageNumL);
+ }
+
+ for(i=r.bottom-gridY*15/8; i>r.top+gridY; i-=gridY)
+ {
+ dc->TextOut(r.left + gridX / 2 + penPageWidth / 4, i, pageNum, pageNumL);
+ dc->TextOut(r.right- gridX / 2 - penPageWidth / 4, i, pageNum, pageNumL);
+ }
+ } // end if page visible
+ } // end for pages
+
+ dc->SetBkMode(OPAQUE);
+ dc->SelectObject(whiteBrush);
+ dc->SelectObject(&penEdge); // Before destroying penPage
+ }
+ else // not showing pages
+ dc->SelectObject(&penEdge);
+#else
+ dc->setPen(penEdge);
+#endif
+
+ // Draw the background grid:
+ if (showGrid)// && (zoom >= minZoomGrid))//&& !dc->IsPrinting())
+ {
+#if 0
+printf(" Preparing to draw grid...\n");
+// dc->SetBkMode(TRANSPARENT);
+// dc->SelectObject(&penGrid);
+ dc->setBrush(Qt::NoBrush);
+ dc->setPen(penGrid);
+
+ QRect clip;
+// dc->GetClipBox(&clip);
+// clip = dc->viewport();
+// clip = dc->window();
+ clip = geometry();
+printf(" clip = %i, %i, %i, %i\n", clip.x(), clip.y(), clip.width(), clip.height());
+
+ clip.setLeft(clip.left() - (clip.left() % gridX));
+ clip.setBottom(clip.bottom() - (clip.bottom() % gridY + gridY));
+
+ if (clip.top() < -gridY)
+ clip.setTop(clip.top() + gridY);
+
+ QSize docSize(doc->getDocSize());
+ docSize.setHeight(docSize.height() * -1);
+
+ if (clip.right() > docSize.width())
+ clip.setRight(docSize.width());
+
+ if (clip.bottom() < docSize.height())
+ clip.setBottom(docSize.height());
+
+printf(" clip = %i, %i, %i, %i; docSize = %i, %i\n", clip.left(), clip.right(), clip.bottom(), clip.top(), docSize.width(), docSize.height());
+ for(i=clip.left(); i<=clip.right(); i+=gridX)
+ {
+ dc->drawLine(i, 0, i, docSize.height());
+ }
+
+// for(i=clip.bottom(); i<=clip.top(); i+=gridY)
+ for(i=-clip.bottom(); i<=clip.top(); i+=gridY)
+ {
+// dc->drawLine(0, i, docSize.width(), i);
+ dc->drawLine(0, i, docSize.width(), i);
+ }
+
+// dc->SetBkMode(OPAQUE);
+#else
+ dc->setBrush(Qt::NoBrush);
+ dc->setPen(penGrid);
+ QSize docSize(doc->docSize);
+
+ for(int i=0; i<=docSize.width(); i+=gridX)
+ dc->drawLine(i, 0, i, docSize.height());
+
+ for(int i=0; i<=docSize.height(); i+=gridY)
+ dc->drawLine(0, i, docSize.width(), i);
+#endif
+ }
+
+ // Draw the room connections
+ int i = doc->edge.size();
+ EdgeConstItr edge = doc->edge.end() - 1;
+ RoomConstItr room = doc->room.v.begin();
+ dc->setPen(penEdge);
+
+ while (i-- > 0)
+ {
+ QPoint start, end;
+
+ doc->getEdgePoints(*edge, start, end);
+
+ // Offset the edge if we're dragging it...
+ if (opInProgress >= gmoDrag)
+ {
+ if (selected[edge->room1])
+ start += p2Tmp;
+
+ if ((selected[edge->room1] && (edge->type1 & etNoRoom2))
+ || selected[edge->room2])
+ end += p2Tmp;
+ }
+
+ if (edge->type1 & etObstructed)
+ dc->setPen(hoveredEdge == i ? penEdgeDashedHover : penEdgeDashed);
+ else
+ dc->setPen(hoveredEdge == i ? penEdgeHover : penEdge);
+
+ dc->drawLine(start, end);
+
+ if (edge->type1 & etOneWay)
+ {
+ dc->save();
+ dc->setBrush(Qt::black);
+ DrawArrowhead(dc, end, start);
+ dc->restore();
+ }
+ else if (edge->type1 & etNoExit)
+ {
+ DrawNoExit(dc, end, start);
+ }
+ else if (edge->type1 & etLoopBack)
+ {
+ const double angle = Angle(start - end);
+ const double orthoAngle = angle + QTR_TAU;
+ const double size = 5.0;
+
+ QPointF ortho(cos(orthoAngle), sin(orthoAngle));
+ QPointF unit = UnitVector(end - start);
+
+ QPointF p1 = start + (ortho * 6.0 * size);
+ QPointF p2 = end + (ortho * 6.0 * size);
+ QPointF p3 = end + (ortho * 3.0 * size);
+ p3.rx() -= 3.0 * size;
+ p3.ry() -= 3.0 * size;
+ dc->drawLine(p1, p2);
+ QRectF r(p3, QSizeF(6.0 * size, 6.0 * size));
+ // Because painter.drawArc() uses a Cartesian (non-Y-inverted) coordinate system to determine its angles, we have to invert our Y-coords to get correct angles to feed to it. :-/
+ QPoint funnyStart(start.x(), start.y() * -1), funnyEnd(end.x(), end.y() * -1);
+ double funnyAngle = Angle(funnyStart - funnyEnd);
+ dc->drawArc(r, (int)((funnyAngle + QTR_TAU) * RADIANS_TO_DEGREES) * 16, 180 * 16);
+ dc->save();
+ dc->setBrush(Qt::black);
+ DrawArrowhead(dc, p1, p2);
+ dc->restore();
+ }
+
+ char elBuf[2] = "?";
+
+ if (edge->type1 & etDirection)
+ {
+ const QPoint & p = room[edge->room1]->pos;
+// dc->TextOut(p.x + edgLblXOffset[edge->end1], p.y + edgLblYOffset[edge->end1], &edgeLabel[(edge->type1 & etDirection) - 1], 1);
+ elBuf[0] = edgeLabel[(edge->type1 & etDirection) - 1];
+ dc->drawText(p + edgLblOffset[edge->end1], elBuf);
+ }
+
+ if (edge->type2 & etDirection)
+ {
+ const QPoint & p = room[edge->room2]->pos;
+// dc->TextOut(p.x + edgLblXOffset[edge->end2], p.y + edgLblYOffset[edge->end2], &edgeLabel[(edge->type2 & etDirection) - 1], 1);
+ elBuf[0] = edgeLabel[(edge->type2 & etDirection) - 1];
+ dc->drawText(p + edgLblOffset[edge->end2], elBuf);
+ }
+
+ edge--;
+ }
+
+ // Draw the rooms
+ dc->setPen(penRoom);
+ bool focused = false;
+ i = 0;
+
+ for(const int count=doc->room.size(); i<count; i++, room++)
+ {
+ QRect r = (*room)->getRect();
+ QPoint cp = (*room)->GetCenter();
+
+ // Translate room if dragging operation in progress
+ if ((opInProgress >= gmoDrag) && selected[i])// && !(*room)->isCorner())
+ {
+ r.translate(p2Tmp.x(), p2Tmp.y());
+ cp += p2Tmp;
+ }
+
+// if (!dc->RectVisible((*room)->getRect(r)))
+// if (!r.intersects(dc->viewport()))
+// continue;
+
+ const bool selectedI = (selected[i] != 0);
+
+ if (selectedI != focused)
+ focused = selectedI;
+
+ bool hovered = r.contains(mouse);
+ RoomCorner rc = rcNone;
+
+ if (hovered)
+ rc = doc->CornerHit(mouse - r.topLeft());
+
+ dc->setPen(hovered ? penEdgeHover : penRoom);
+
+ dc->setBrush(focused ? focusBrush : Qt::white);
+
+ bool needOpaqueText = false;
+
+ if ((*room)->flags & rfBorder)
+ {
+ dc->drawRect(r);
+ }
+ else if (focused)
+ {
+ dc->setBrush(focusBrush);
+ dc->drawRect(r);
+ }
+ else // Room has no border and is not focused
+ needOpaqueText = !(*room)->name.empty();
+
+ if ((*room)->isCorner() && (focused || showCorners))
+ {
+ QRect centerRect(cp - QPoint(20, 20), QSize(40, 40));
+ dc->save();
+ dc->setPen(Qt::black);
+ dc->setBrush(Qt::black);
+ dc->drawEllipse(centerRect);
+ dc->restore();
+ }
+
+// dc->SetBkMode(TRANSPARENT);
+
+ if ((rc >= 0) && (rc <= 11) && ((*room)->isCorner() == false))
+ {
+ QRect rCrnr = cornerRect[rc].translated(r.topLeft());
+// rCrnr.translate(r.topLeft());
+ dc->save();
+ dc->setPen(Qt::NoPen);
+ dc->setBrush(Qt::green);
+ dc->drawRect(rCrnr);
+ dc->restore();
+ }
+
+ if (!(*room)->note.empty())
+ {
+ QPoint noteOffset(roomWidth - 29, 57);
+
+ dc->save();
+ dc->setPen(QColor(0xFF, 0x00, 0x00));
+ dc->drawText(r.topLeft() + noteOffset, "*");
+ dc->restore();
+ }
+
+// if (needOpaqueText)
+// dc->SetBkMode(OPAQUE);
+
+ // Shrink the rect left/right margins just a bit
+ QMargins margin(20, 0, 20, 0); // LTRB
+ r = r.marginsRemoved(margin);
+//dc->save();
+//dc->setPen(Qt::blue);
+//dc->drawRect(r);
+//dc->restore();
+
+ dc->drawText(r, Qt::AlignCenter | Qt::TextWordWrap, (*room)->name.c_str());
+
+// dc->SetBkMode(OPAQUE);
+ }
+
+ // JLH: Draw special stuffs (crap that was stuffed into OnMouseDown & OnMouseMove & the like...
+ if (opInProgress == gmoSelectBox)
+ {
+ dc->setPen(QPen(QColor(0x00, 0xFF, 0x00, 0xFF)));
+ dc->setBrush(QBrush(QColor(0x00, 0xFF, 0x00, 0x64)));
+ dc->drawRect(rTmp);
+ }
+ else if (opInProgress == gmoAddEdge)
+ {
+ dc->setPen(penEdge);
+ dc->drawLine(p1Tmp, p2Tmp);
+ }
+}
+
+
+void MapView::keyPressEvent(QKeyEvent * event)
+{
+ bool oldShift = shiftDown;
+ bool oldCtrl = ctrlDown;
+ bool oldAlt = altDown;
+
+ if (event->key() == Qt::Key_Shift)
+ shiftDown = true;
+ else if (event->key() == Qt::Key_Control)
+ ctrlDown = true;
+ else if (event->key() == Qt::Key_Alt)
+ altDown = true;
+
+ double oldZoom = zoom;
+
+ if (event->key() == Qt::Key_0)
+ zoom = 100.0;
+ else if (event->key() == Qt::Key_9)
+ zoom = 90.0;
+ else if (event->key() == Qt::Key_8)
+ zoom = 80.0;
+ else if (event->key() == Qt::Key_7)
+ zoom = 70.0;
+ else if (event->key() == Qt::Key_6)
+ zoom = 60.0;
+ else if (event->key() == Qt::Key_5)
+ zoom = 50.0;
+ else if (event->key() == Qt::Key_4)
+ zoom = 40.0;
+ else if (event->key() == Qt::Key_3)
+ zoom = 30.0;
+ else if (event->key() == Qt::Key_2)
+ zoom = 20.0;
+ else if (event->key() == Qt::Key_1)
+ zoom = 10.0;
+
+ if (zoom != oldZoom)
+ update();
+
+#if 0
+ if ((oldShift != shiftDown) || (oldCtrl != ctrlDown))
+ {
+ if (Global::tool)
+ ToolHandler(ToolKeyDown, Point(0, 0));
+
+ update();
+ }
+#endif
+
+ if (oldAlt != altDown)
+ {
+ scrollDrag = true;
+ setCursor(Qt::SizeAllCursor);
+// oldPoint = oldScrollPoint;
+ }
+
+#if 0
+ if (select.size() > 0)
+ {
+ if (event->key() == Qt::Key_Up)
+ {
+ TranslateObjects(select, Point(0, +1.0));
+ update();
+ }
+ else if (event->key() == Qt::Key_Down)
+ {
+ TranslateObjects(select, Point(0, -1.0));
+ update();
+ }
+ else if (event->key() == Qt::Key_Right)
+ {
+ TranslateObjects(select, Point(+1.0, 0));
+ update();
+ }
+ else if (event->key() == Qt::Key_Left)
+ {
+ TranslateObjects(select, Point(-1.0, 0));
+ update();
+ }
+ }
+#endif
+}
+
+
+void MapView::keyReleaseEvent(QKeyEvent * event)
+{
+ bool oldShift = shiftDown;
+ bool oldCtrl = ctrlDown;
+ bool oldAlt = altDown;
+
+ if (event->key() == Qt::Key_Shift)
+ shiftDown = false;
+ else if (event->key() == Qt::Key_Control)
+ ctrlDown = false;
+ else if (event->key() == Qt::Key_Alt)
+ altDown = false;
+
+#if 0
+ if ((oldShift != shiftDown) || (oldCtrl != ctrlDown))
+ {
+ if (Global::tool)
+ ToolHandler(ToolKeyUp, Point(0, 0));
+
+ update();
+ }
+#endif
+
+ if (oldAlt != altDown)
+ {
+ scrollDrag = false;
+ setCursor(Qt::ArrowCursor);
+ }
+}
+
+
+#if 0
+/////////////////////////////////////////////////////////////////////////////
+// CMapView printing
+//--------------------------------------------------------------------
+// Record which page we're printing, if any:
+//
+// Output Variables:
+// printingPage
+
+void MapView::OnPrepareDC(QPainter * dc, CPrintInfo * pInfo)
+{
+ CScrollZoomView::OnPrepareDC(dc, pInfo);
+
+ if (pInfo)
+ printingPage = pInfo->m_nCurPage;
+ else
+ printingPage = 0;
+}
+
+
+bool MapView::OnPreparePrinting(CPrintInfo * pInfo)
+{
+ // Require registration before printing map with more than 10 rooms:
+ MapDoc * const doc = GetDocument();
+ ASSERT_VALID(doc);
+
+ if (doc->needRepaginate())
+ {
+ CRepaginateDlg d;
+
+ switch (d.DoModal())
+ {
+ case IDCANCEL:
+ return false;
+ case IDYES:
+ doc->layoutPages();
+ break;
+ }
+ }
+
+ pInfo->SetMaxPage(doc->page.size());
+ return DoPreparePrinting(pInfo);
+}
+
+
+void MapView::OnBeginPrinting(QPainter * /*pDC*/, CPrintInfo * /*pInfo*/)
+{
+ // Don't show selection or corners while printing:
+ // We do this here instead of OnPreparePrinting, because OnEndPrinting
+ // is only guaranteed to be called if OnBeginPrinting is.
+ clearSelection();
+ selectDone();
+ showCorners = false;
+}
+
+
+void MapView::OnEndPrinting(QPainter* /*pDC*/, CPrintInfo* /*pInfo*/)
+{
+ if (GetDocument()->locked)
+ OnUpdate(NULL, dupNavigationMode, NULL); // Select a room
+}
+#endif
+
+
+//
+// CMapView miscellaneous
+//
+// Add a room:
+//
+// Input:
+// point: The point where the mouse was clicked (in logical coordinates)
+//
+void MapView::addRoom(QPoint & point)
+{
+ QSize docSize(doc->docSize);
+
+ if (doc->locked || (point.x() > docSize.width()) || (point.y() > docSize.height()))
+ {
+// MessageBeep(MB_ICONASTERISK);
+ return;
+ }
+
+ point.rx() -= roomWidth / 2 - gridX / 2;
+ point.rx() -= point.x() % gridX;
+ point.ry() -= roomHeight / 2 - gridY / 2;
+ point.ry() -= point.y() % gridY;
+
+ if (point.x() < 0)
+ point.setX(0);
+ else if (point.x() + roomWidth > docSize.width())
+ point.setX(docSize.width() - roomWidth);
+
+ if (point.y() < 0)
+ point.setY(0);
+ else if (point.y() + roomHeight > docSize.height())
+ point.setY(docSize.height() - roomHeight);
+
+ clearSelection();
+ const bool wasModified = doc->isDirty;
+ const int rNum = doc->addRoom(point);
+
+ if (rNum >= 0)
+ selectRoom(rNum);
+
+ selectDone(); // FIXME disable floating comments
+ editProperties(epuAddRoom, wasModified);
+}
+
+
+//
+// Make sure we aren't dragging a room off the edge:
+//
+// Input:
+// p: The proposed offset for the selected rooms
+//
+// Input Variables:
+// rTmp: Rectangle enclosing the original positions of the selected rooms
+//
+// Output:
+// p: The corrected (if necessary) offset for selected rooms
+//
+void MapView::adjustOffset(QPoint & p) const
+{
+ const QSize size(doc->docSize);
+
+ if (p.x() + rTmp.left() < 0)
+ p.rx() = -rTmp.left();
+
+ if (p.x() + rTmp.right() > size.width())
+ p.rx() = size.width() - rTmp.right();
+
+ if (p.y() + rTmp.top() < 0)
+ p.ry() = -rTmp.top();
+
+ if (p.y() + rTmp.bottom() > size.height())
+ p.ry() = size.height() - rTmp.bottom();
+}
+
+
+//
+// Deselect all rooms:
+//
+// Input:
+// update: TRUE means the selected rooms should be redrawn
+//
+void MapView::clearSelection(bool update/* = true*/)
+{
+ if (doc->room.size() != selected.size())
+ selected.resize(doc->room.size(), 0);
+
+ if (update && numSelected)
+ {
+#if 0
+ QRect r;
+ CClientDC dc(this);
+ OnPrepareDC(&dc);
+ RoomConstItr room = doc->room.getVector().begin();
+
+ for(int i=doc->room.size()-1; numSelected && i>=0; --i)
+ {
+ if (selected[i])
+ {
+ numSelected--;
+ room[i]->getRect(r);
+ dc.LPtoDP(r);
+ r.NormalizeRect();
+ InvalidateRect(r);
+ }
+ }
+#endif
+ }
+
+ numSelected = 0;
+
+ for(ByteItr b=selected.begin(); b!=selected.end(); ++b)
+ *b = 0;
+
+ deselectPages(update);
+}
+
+
+//
+// Compute a rectangle enclosing all selected rooms:
+//
+// Input Variables:
+// numSelected
+// numSelectedPages
+// selected
+// selectedPage
+//
+// Output:
+// r: A rectangle enclosing all selected rooms
+//
+void MapView::computeSelectedRect(QRect & r) const
+{
+// r.SetRectEmpty();
+ r = QRect();
+
+ if (numSelected)
+ {
+ RoomConstItr room = doc->room.getVector().begin();
+
+ for(int i=doc->room.size()-1; i>=0; i--)
+ {
+ if (selected[i])
+ r |= room[i]->getRect();
+ }
+ }
+
+ if (numSelectedPages)
+ {
+ for(int i=doc->page.size()-1; i>=0; i--)
+ {
+ if (selectedPage[i])
+ r |= doc->getPageRect(i);
+ }
+ }
+}
+
+
+//
+// Deselect a page:
+//
+// Input:
+// n: The page number to be deselected
+// update: TRUE means the page should be redrawn if necessary
+//
+// Output Variables:
+// numSelectedPages
+// selectedOne
+// selectedPage
+//
+void MapView::deselectPage(int n, bool update/* = true*/)
+{
+ ASSERT((n >= 0) && (n < doc->page.size()));
+
+ if (selectedPage[n])
+ {
+ selectedPage[n] = false;
+
+ if ((--numSelectedPages == 0) && (numSelected == 1))
+ {
+ for(selectedOne=0; !selected[selectedOne]; selectedOne++)
+ ; // Find the selected room
+ }
+ else
+ selectedOne = -1;
+
+#if 0
+ if (update)
+ {
+ CClientDC dc(this);
+ OnPrepareDC(&dc);
+ QRect r;
+ doc->getPageRect(n, r);
+ dc.LPtoDP(r);
+ r.NormalizeRect();
+ InvalidateRect(r);
+ }
+#endif
+ }
+}
+
+
+//
+// Deselect all pages:
+//
+// Input:
+// update: TRUE means the selected pages should be redrawn
+//
+// Output Variables:
+// numSelectedPages
+// selectedOne
+// selectedPage
+//
+void MapView::deselectPages(bool update/* = true*/)
+{
+ ASSERT(selectedPage.size() == doc->page.size());
+
+ if (update && numSelectedPages)
+ {
+ QRect r;
+// CClientDC dc(this);
+// OnPrepareDC(&dc);
+
+ for(int i=doc->page.size()-1; numSelectedPages&&i>=0; i--)
+ {
+ if (selectedPage[i])
+ {
+ numSelectedPages--;
+ r = doc->getPageRect(i);
+
+ if (!showPages)
+ {
+ // make sure it disappears
+ r.setBottom(r.bottom() + penPageWidth);
+ r.setLeft(r.left() - penPageWidth);
+ }
+
+// dc.LPtoDP(r);
+// r.NormalizeRect();
+// InvalidateRect(r);
+ }
+ }
+ }
+
+ numSelectedPages = 0;
+
+ for(ByteItr b=selectedPage.begin(); b!=selectedPage.end(); b++)
+ *b = 0;
+
+ if (numSelected == 1)
+ {
+ for(selectedOne=0; !selected[selectedOne]; selectedOne++)
+ ; // Find the selected room
+ }
+ else
+ selectedOne = -1;
+}
+
+
+//
+// Deselect a room:
+//
+// Input:
+// n: The room number to be deselected
+// update: TRUE means the room should be redrawn if necessary
+//
+// Output Variables:
+// numSelected
+// selectedOne
+// selected
+//
+void MapView::deselectRoom(RoomNum n, bool update/* = true*/)
+{
+ ASSERT((n >= 0) && (n < doc->room.size()));
+
+ if (doc->room.size() != selected.size())
+ selected.resize(doc->room.size(), 0);
+
+ if (selected[n])
+ {
+ selected[n] = false;
+
+ if ((--numSelected == 1) && !numSelectedPages)
+ {
+ for (selectedOne=0; !selected[selectedOne]; selectedOne++)
+ ; // Find the selected room
+ }
+ else
+ selectedOne = -1;
+
+#if 0
+ if (update)
+ {
+ CClientDC dc(this);
+ OnPrepareDC(&dc);
+ QRect r;
+ doc->room[n].getRect(r);
+ dc.LPtoDP(r);
+ r.NormalizeRect();
+ InvalidateRect(r);
+ }
+#endif
+ }
+}
+
+
+//
+// Update the room comments dialog after the selection changes:
+//
+void MapView::selectDone()
+{
+// static_cast<CMapApp *>(AfxGetApp())->setComment(this, (selectedOne >= 0 ? &(GetDocument()->getRoom(selectedOne)) : NULL));
+}
+
+
+//
+// Select a page:
+//
+// Input:
+// n: The page number to select
+// update: TRUE means the selected page should be redrawn if necessary
+//
+// Output Variables:
+// numSelectedPages
+// selectedOne
+// selectedPage
+//
+void MapView::selectPage(int n, bool update/* = true*/)
+{
+ if (!selectedPage[n])
+ {
+ selectedPage[n] = true;
+ numSelectedPages++;
+ selectedOne = -1;
+
+#if 0
+ if (update)
+ {
+ CClientDC dc(this);
+ OnPrepareDC(&dc);
+ QRect r;
+ doc->getPageRect(n, r);
+ dc.LPtoDP(r);
+ r.NormalizeRect();
+ InvalidateRect(r);
+ }
+#endif
+ }
+}
+
+
+//
+// Select a room:
+//
+// Input:
+// n: The room number to select
+// update: TRUE means the selected room should be redrawn if necessary
+//
+// Output Variables:
+// numSelected
+// selectedOne
+// selected
+//
+void MapView::selectRoom(RoomNum n, bool update/*= true*/)
+{
+ if (doc->room.size() != selected.size())
+ selected.resize(doc->room.size(), 0);
+
+ if (!selected[n])
+ {
+ selected[n] = true;
+
+ if ((++numSelected == 1) && !numSelectedPages)
+ selectedOne = n;
+ else
+ selectedOne = -1;
+
+#if 0
+ if (update)
+ {
+ CClientDC dc(this);
+ OnPrepareDC(&dc);
+ QRect r;
+ doc->room[n].getRect(r);
+ dc.LPtoDP(r);
+ r.NormalizeRect();
+ InvalidateRect(r);
+ }
+#endif
+ }
+}
+
+
+void MapView::selectOnlyRoom(RoomNum n)
+{
+ if (selectedOne != n)
+ {
+ clearSelection();
+ selectRoom(n);
+ selectDone();
+ }
+}
+
+
+//
+// Make sure that a room is visible:
+//
+// Input:
+// n: The number of the room to be made visible
+//
+void MapView::makeRoomVisible(RoomNum n)
+{
+#if 0
+ QRect clientRect;
+ GetClientRect(&clientRect);
+ QSize viewSize(clientRect.right, clientRect.bottom);
+
+ CClientDC cdc(this);
+ OnPrepareDC(&cdc);
+ cdc.DPtoLP(&viewSize);
+
+ const QSize docSize(doc->getDocSize());
+ const QPoint curPos(getScrollPosition());
+ QRect roomRect;
+ doc->room[n].getRect(roomRect);
+
+ QPoint newPos(curPos);
+
+ if (roomRect.left - curPos.x < gridX)
+ {
+ newPos.x -= curPos.x - roomRect.left + gridX;
+
+ if (newPos.x < 0)
+ newPos.x = 0;
+ }
+ else if (roomRect.right - curPos.x + gridX > viewSize.cx)
+ {
+ newPos.x += roomRect.right + gridX - viewSize.cx - curPos.x;
+
+ if (newPos.x + viewSize.cx > docSize.cx)
+ newPos.x = docSize.cx - viewSize.cx;
+ }
+
+ if (curPos.y - roomRect.bottom < gridY)
+ {
+ newPos.y += roomRect.bottom + gridY - curPos.y;
+
+ if (newPos.y > 0)
+ newPos.y = 0;
+ }
+ else if (curPos.y - roomRect.top + gridY > viewSize.cy)
+ {
+ newPos.y += roomRect.top + viewSize.cy - curPos.y - gridY;
+
+ if (viewSize.cy - newPos.y > docSize.cy)
+ newPos.y = viewSize.cy - docSize.cy;
+ }
+
+ if (newPos != curPos)
+ {
+ scrollToPosition(newPos);
+ // Must adjust the room position because the DC won't be updated:
+ roomRect.OffsetRect(curPos.x - newPos.x, curPos.y - newPos.y);
+ }
+
+ // Make sure the floating comments dialog isn't in the way:
+ cdc.LPtoDP(&roomRect);
+ ClientToScreen(&roomRect);
+ roomRect.NormalizeRect();
+ static_cast<CMapApp *>(AfxGetApp())->adjustCommentPos(roomRect);
+#endif
+}
+
+
+//
+// Paste a string to the clipboard:
+//
+// Input:
+// text: The string to paste
+//
+// Returns:
+// True: String was successfully pasted
+// False: Could not paste (clipboard unavailable or out of memory)
+//
+bool MapView::pasteClipboard(const string & text)
+{
+#if 0
+ if (!OpenClipboard())
+ return false;
+
+ EmptyClipboard();
+
+ // Allocate a global memory object for the text
+ HGLOBAL mem = GlobalAlloc(GMEM_DDESHARE, text.length() + sizeof(TCHAR));
+
+ if (mem == NULL)
+ {
+ CloseClipboard();
+ return false;
+ }
+
+ // Lock the handle and copy the text to the buffer
+
+ strcpy(LPTSTR(GlobalLock(mem)), text.c_str());
+ GlobalUnlock(mem);
+
+ SetClipboardData(CFtrEXT, mem); // Place the handle on the clipboard
+ CloseClipboard();
+#endif
+
+ return true;
+}
+
+
+//
+// Update the selected room's comment from the floating dialog:
+//
+// Input:
+// comment: The new room comment (must not be NULL)
+//
+void MapView::setRoomNote(const char * comment)
+{
+ ASSERT(selectedOne >= 0);
+
+ if (doc->room[selectedOne].note != comment)
+ {
+ doc->setUndoData(new UndoRoomInfo(*doc, selectedOne));
+ doc->setRoomNote(selectedOne, comment);
+ }
+}
+
+
+int MapView::FindHoveredEdge(void)
+{
+ for(int i=0; i<doc->edge.size(); i++)
+ {
+ QPoint ep1, ep2;
+
+ doc->getEdgePoints(doc->edge[i], ep1, ep2);
+
+ QPointF lineSegment = ep2 - ep1;
+ QPointF v1 = mouse - ep1;
+ QPointF v2 = mouse - ep2;
+ double t = ParameterOfLineAndPoint(ep1, ep2, mouse);
+ double distance;
+
+ if (t < 0.0)
+ distance = Magnitude(v1);
+ else if (t > 1.0)
+ distance = Magnitude(v2);
+ else
+ // distance = ?Det?(ls, v1) / |ls|
+ distance = fabs(Determinant(lineSegment, v1)
+ / Magnitude(lineSegment));
+
+ if (distance < 20.0)
+ return i;
+ }
+
+ // Didn't find a closely hovered edge
+ return -1;
+}
+
+
+//
+// Set the step size of the scroll bars:
+//
+void MapView::setScrollBars()
+{
+#if 0
+ QRect clientRect;
+ GetClientRect(&clientRect);
+ QSize viewSize(clientRect.right, clientRect.bottom);
+
+ CClientDC cdc(this);
+ OnPrepareDC(&cdc);
+ cdc.DPtoLP(&viewSize);
+
+ viewSize.cx -= gridX / 2;
+ viewSize.cx -= viewSize.cx % gridX + roomWidth;
+ viewSize.cx = max(viewSize.cx, gridX);
+
+ viewSize.cy -= gridY / 2;
+ viewSize.cy -= viewSize.cy % gridY + roomHeight;
+ viewSize.cy = max(viewSize.cy, gridY);
+
+ setPageStep(viewSize);
+#endif
+}
+
+
+//
+// Zoom the display:
+//
+// Input:
+// newZoom: The new zoom factor (in percent)
+//
+void MapView::zoomTo(short newZoom)
+{
+ if (opInProgress == gmoAddCorner)
+ opInProgress = gmoNone;
+
+ if (newZoom == zoom)
+ return;
+
+ if (opInProgress || scrollDrag || (newZoom < minZoom) || (newZoom > maxZoom))
+ ;//MessageBeep(MB_OK);
+ else
+ {
+// setDisplayZoom(zoom = newZoom);
+
+ if (selectedOne >= 0)
+ makeRoomVisible(selectedOne);
+
+ setScrollBars();
+// GetParentFrame()->OnUpdateFrameTitle(TRUE);
+ }
+}
+
+
+//
+// Navigation:
+//---------------------------------------------------------------------------
+// Keyboard navigation:
+//
+// Input:
+// corner: The direction to move
+// toggleStubs: TRUE means adding an existing stub should delete it
+//
+// Input Variables:
+// edgeTmp: If type1 or type2 is nonzero, use that for a new edge
+// selectedOne: Must be a valid room number
+//
+void MapView::navigate(RoomCorner corner, bool toggleStubs/* = true*/)
+{
+ const short roomXoffset[] =
+ {
+ 0, 0, gridX + roomWidth, -(gridX + roomWidth),
+ gridX + roomWidth, -(gridX + roomWidth), gridX + roomWidth, -(gridX + roomWidth)
+ }; // FIXME add NNE, etc.
+
+ const short roomYoffset[] =
+ {
+ gridY + roomHeight, -(gridY + roomHeight), 0, 0,
+ gridY + roomHeight, gridY + roomHeight, -(gridY + roomHeight), -(gridY + roomHeight)
+ }; // FIXME add NNE, etc.
+
+ MapEdge e;
+
+ ASSERT(selectedOne >= 0);
+
+ if (doc->room[selectedOne].isCorner())
+ {
+// MessageBeep(MB_ICONASTERISK);
+ return;
+ }
+
+ // Look for an existing connection:
+ int eNum = doc->findEdge(selectedOne, corner, e);
+
+ if ((eNum >= 0) && !(e.type2 & etUnexplored))
+ {
+ // Found existing connection, and 2nd end is not explored
+ if (toggleStubs && (e.type2 & etNoExit))
+ {
+ if (edgeTmp.type1 & etNoExit)
+ {
+ doc->setUndoData(new UndoDelete(doc->isDirty, doc->edge[eNum]));
+ }
+ else
+ {
+ doc->setUndoData(new UndoChangeEdge(doc->isDirty, doc->edge[eNum]));
+ edgeTmp.room1 = selectedOne;
+ edgeTmp.end1 = corner;
+ doc->addEdge(edgeTmp);
+ }
+
+ doc->deleteEdge(eNum);
+ return;
+ }
+
+ if (edgeTmp.type1 || edgeTmp.type2 || (e.type1 & etOneWay)
+ || (e.type2 & etNoRoom2))
+ {
+ // We were trying to add connection
+// MessageBeep(MB_ICONASTERISK);
+ return;
+ }
+
+ if (e.end1 == rcCorner)
+ {
+ int r = doc->findOtherEnd(eNum);
+
+ if (r >= 0)
+ e.room1 = r;
+ else
+ {
+// MessageBeep(MB_ICONASTERISK);
+ return;
+ }
+ } // end if this connection leads to a corner
+
+ selectOnlyRoom(e.room1);
+ makeRoomVisible(e.room1);
+ eNum = -1; // Don't delete this edge
+ }
+ else // eNum < 0 || e.type2 & etUnexplored
+ {
+ // Try to add a new connection
+ if (doc->locked || (corner >= rcNNE))
+ {
+// MessageBeep(MB_ICONASTERISK);
+ return;
+ }
+
+ const bool wasModified = doc->isDirty;
+ bool added = false;
+
+ // If adding stub where there's already a stub
+ if ((eNum >= 0) && (e.type2 & etUnexplored)
+ && (edgeTmp.type1 & etUnexplored))
+ {
+ if (toggleStubs)
+ {
+ // Remove stub connection:
+ doc->setUndoData(new UndoDelete(wasModified, doc->edge[eNum]));
+ doc->deleteEdge(eNum);
+ }
+// else
+// MessageBeep(MB_ICONASTERISK);
+
+ return;
+ }
+
+ e.room1 = selectedOne;
+ e.end1 = corner;
+
+ if (edgeTmp.type1 || edgeTmp.type2)
+ {
+ e.type1 = edgeTmp.type1;
+ e.type2 = edgeTmp.type2;
+ }
+ else
+ setEdgeType(e);
+
+ EdgeVec deletedEdges;
+
+ // If there's a room #2 connected to this corner of the room...
+ if (!(e.type1 & etNoRoom2))
+ {
+ QPoint pos(doc->room[selectedOne].pos);
+ pos.rx() += roomXoffset[corner];
+ pos.ry() += roomYoffset[corner];
+
+ int room = doc->findRoom(pos);
+
+ if (room < -1)
+ {
+ // We're off the grid
+// MessageBeep(MB_ICONASTERISK);
+ return;
+ }
+ else if (room < 0)
+ {
+ // We need to add a new room
+ room = doc->addRoom(pos);
+ added = true;
+ }
+ else
+ {
+ // Existing room, check for existing connection
+ MapEdge oEdge;
+ int oeNum = doc->findEdge(room, oppositeCorner[corner], oEdge);
+
+ if (oeNum >= 0)
+ { // There is an existing connection
+ if (oEdge.type2 & etUnexplored)
+ {
+ deletedEdges.push_back(doc->edge[oeNum]);
+ doc->deleteEdge(oeNum);
+
+ if (eNum > oeNum)
+ eNum--; // The edge number might have changed
+ }
+ else
+ room = -1; // Room has a non-stub connection there
+ }
+ }
+
+ if (room < 0)
+ {
+// MessageBeep(MB_ICONASTERISK);
+ return;
+ }
+
+ selectOnlyRoom(room);
+ makeRoomVisible(room);
+
+ e.room2 = room;
+ e.end2 = oppositeCorner[corner];
+ }
+
+ if (eNum >= 0)
+ {
+ deletedEdges.push_back(doc->edge[eNum]);
+ doc->deleteEdge(eNum);
+ }
+
+ doc->addEdge(e);
+
+#if 0
+ if (added)
+ {
+ // Enter room name
+ if (gueApp()->editAfterAdd()) //editAfterAdd() returns autoEdit
+ editProperties(epuAddRoomEdge, wasModified, (deletedEdges.size() ? &deletedEdges : NULL));
+ else if (deletedEdges.size())
+ doc->setUndoData(new UndoChanges(wasModified, selectedOne, 1, deletedEdges));
+ else
+ doc->setUndoData(new UndoAdd(wasModified, selectedOne, 1));
+ }
+ else if (deletedEdges.size())
+ {
+ if (deletedEdges.size() == 1)
+ doc->setUndoData(new UndoChangeEdge(wasModified, deletedEdges[0]));
+ else
+ doc->setUndoData(new UndoChanges(wasModified, -1, 1, deletedEdges));
+ }
+ else
+ doc->setUndoData(new UndoAdd(wasModified)); // Undo new edge
+#endif
+ }
+}
+
+
+//
+// Fill in the edge type from the navigation box:
+//
+// If the text in the navigation bar is up, down, in, or out, then set
+// the edge type appropriately. Otherwise, set the edge type to normal.
+// Always clears the navigation bar text.
+//
+// Can only create up-down and in-out passages.
+//
+// Output:
+// e.type1 and e.type2
+//
+void MapView::setEdgeType(MapEdge & e)
+{
+ e.type1 = e.type2 = etNormal;
+
+ RoomCorner corner1, corner2;
+ char initial, separator;
+ getNavText(initial, corner1, separator, corner2);
+
+ if (initial && initial != '%' && initial != '>')
+ {
+// MessageBeep(MB_ICONASTERISK);
+ return;
+ }
+
+ if (separator)
+ {
+ switch (corner1)
+ {
+ case rcUp: e.type1 = etUp; break;
+ case rcDown: e.type1 = etDown; break;
+ case rcIn: e.type1 = etIn; break;
+ case rcOut: e.type1 = etOut; break;
+ }
+
+ if (separator == '-')
+ {
+ switch (corner2)
+ {
+ case rcUp: e.type2 = etUp; break;
+ case rcDown: e.type2 = etDown; break;
+ case rcIn: e.type2 = etIn; break;
+ case rcOut: e.type2 = etOut; break;
+ }
+ }
+ }
+ else // standard edge
+ {
+ switch (corner1)
+ {
+ case rcUp: e.type1 = etUp; e.type2 = etDown; break;
+ case rcDown: e.type1 = etDown; e.type2 = etUp; break;
+ case rcIn: e.type1 = etIn; e.type2 = etOut; break;
+ case rcOut: e.type1 = etOut; e.type2 = etIn; break;
+ }
+ }
+
+ if (initial == '%')
+ e.type1 |= etObstructed;
+
+ if (initial == '>' || separator == '>')
+ e.type1 |= etOneWay;
+
+ if (initial == '?' || separator == '?')
+ {
+ e.type1 &= ~etSpecial;
+ e.type1 |= etUnexplored;
+ e.room2 = 0;
+ e.end2 = rcSW;
+ }
+ else if (initial == '!' || separator == '!')
+ {
+ e.type1 &= ~etSpecial;
+ e.type1 |= etNoExit;
+ e.room2 = 0;
+ e.end2 = rcSW;
+ }
+}
+
+
+//
+// Start typing in the navigation bar:
+//
+// Stuffs the given char in the navigation bar and sets focus to there.
+//
+// Input:
+// c: The character to put in the navigation bar.
+//
+void MapView::setNavText(char c)
+{
+#if 0
+ CDialogBar & nb = static_cast<CMainFrame *>(AfxGetMainWnd())->wndNavBar;
+
+ string text(c);
+ nb.SetDlgItemText(IDC_NAV_DIR, text);
+ nb.SetFocus();
+ CEdit * dir = static_cast<CEdit *>(nb.GetDlgItem(IDC_NAV_DIR));
+ dir->SetSel(1, 1);
+ dir->SetSel(-1, 2);
+#endif
+}
+
+
+#if 0
+void MapView::OnChar(unsigned int c, unsigned int nRepCnt, unsigned int nFlags)
+{
+ if (((c >= 'A') && (c <= 'Z'))
+ || ((c >= 'a') && (c <= 'z'))
+ || (c == '-') || (c == '!') || (c == '?') || (c == '/')
+ || (c == '>') || (c == '.') || (c == '~') || (c == '`')
+ || (c == '%'))
+ setNavText(c);
+}
+#endif
+
+
+//
+// Parse the text in the navigation bar:
+//
+// Input:
+// mustBeMove: (default FALSE)
+// If TRUE, beep and don't clear text if not a direction.
+// If FALSE, clear text and don't beep even if it's meaningless.
+//
+// Output:
+// initial:
+// The non-alphabetic character beginning the text (0 if none)
+// dir1:
+// The direction indicated by the first direction word
+// rcNone if no direction words
+// separator:
+// The non-alphabetic character following the first direction word
+// 0 if none
+// Must be either '-', '>', or '?'
+// dir2:
+// The direction indicated by the second direction word
+// rcNone if no second direction
+//
+void MapView::getNavText(char & initial, RoomCorner & dir1, char & separator, RoomCorner & dir2, bool mustBeMove)
+{
+#if 0
+ CDialogBar & nb = static_cast<CMainFrame *>(AfxGetMainWnd())->wndNavBar;
+ string text;
+
+ nb.GetDlgItemText(IDC_NAV_DIR, text);
+ text.MakeLower();
+
+ dir1 = dir2 = rcNone;
+ initial = separator = '\0';
+
+ if (!text.IsEmpty() && (text[0] < 'a' || text[0] > 'z'))
+ {
+ initial = text[0];
+ text = text.Mid(1);
+ }
+
+ if (initial == '-')
+ {
+ initial = '\0';
+ separator = '-';
+ }
+ else if (!text.IsEmpty() && (text[0] == '-' || text[0] == '>'))
+ {
+ separator = text[0];
+ text = text.Mid(1);
+ }
+ else
+ {
+ dir1 = parseDirection(text);
+
+ if (!text.IsEmpty() && (text[0]=='-' || text[0]=='>' || text[0]=='?'))
+ {
+ separator = text[0];
+ text = text.Mid(1);
+ }
+ }
+
+ if (separator)
+ dir2 = parseDirection(text);
+
+ if (mustBeMove && (dir1 == rcNone || separator == '-' || ((initial || separator) && (dir1 >= rcNumCorners))))
+ MessageBeep(MB_ICONASTERISK);
+ else
+ {
+ nb.SetDlgItemText(IDC_NAV_DIR, tr(""));
+ SetFocus();
+ }
+#endif
+}
+
+
+#if 0
+//
+// Handle the Go button in the navigation bar:
+//
+void MapView::OnNavGo()
+{
+ if (selectedOne < 0)
+ {
+ MessageBeep(MB_ICONASTERISK);
+ return;
+ }
+
+ RoomCorner corner, junk2;
+ char initial, separator;
+ getNavText(initial, corner, separator, junk2, true);
+
+ if (separator == '-' || junk2 != rcNone)
+ {
+ MessageBeep(MB_ICONASTERISK);
+ return;
+ }
+
+ if (corner != rcNone)
+ {
+ edgeTmp.type1 = edgeTmp.type2 = etNormal;
+
+ if (initial == '%')
+ edgeTmp.type1 = etObstructed;
+
+ if (initial == '>' || separator == '>')
+ edgeTmp.type1 |= etOneWay;
+
+ if (initial == '?' || separator == '?')
+ edgeTmp.type1 = etUnexplored;
+ else if (initial == '!' || separator == '!')
+ edgeTmp.type1 = etNoExit;
+
+ navigate(corner);
+ }
+}
+
+
+//
+// Handle the direction keys on the numeric keypad:
+//
+// Input:
+// cmd: Which command was executed
+//
+void MapView::OnNavGoDir(unsigned int cmd)
+{
+ ASSERT(cmd >= ID_NAV_GO_NORTH && cmd <= ID_NAV_STUB2_OUT);
+
+ if (selectedOne >= 0)
+ {
+ SetFocus();
+ edgeTmp.type1 = edgeTmp.type2 = etNormal;
+ bool toggleStubs = false;
+
+ if (cmd >= ID_NAV_STUB1_NORTH)
+ {
+ if (cmd >= ID_NAV_STUB2_NORTH)
+ {
+ // Stub 2
+ edgeTmp.type1 = (gueApp()->stub1Unexplored() ? etNoExit : etUnexplored);
+ cmd -= ID_NAV_STUB2_NORTH - ID_NAV_GO_NORTH;
+ }
+ else
+ {
+ // Stub 1
+ edgeTmp.type1 = (gueApp()->stub1Unexplored() ? etUnexplored : etNoExit);
+ cmd -= ID_NAV_STUB1_NORTH - ID_NAV_GO_NORTH;
+ }
+
+ toggleStubs = true;
+ }
+
+ navigate(RoomCorner(cmd - ID_NAV_GO_NORTH), toggleStubs);
+ }
+ else
+ MessageBeep(MB_ICONASTERISK);
+}
+
+
+//
+// CMapView message handlers
+//---------------------------------------------------------------------------
+// Update the comments dialog when the view is activated:
+//
+void MapView::OnActivateView(bool bActivate, CView * pActivateView, CView * pDeactiveView)
+{
+ if (bActivate)
+ selectDone(); // Update comments dialog
+
+ CScrollZoomView::OnActivateView(bActivate, pActivateView, pDeactiveView);
+}
+#endif
+
+
+// N.B.: If you click on a corner with no edge coming out of it, it will crash here... !!! FIX !!! [MOSTLY DONE--there's still a way to make it crash with "Add Corner", but I can't remember the specifics...]
+//void MapView::OnEditAddCorner()
+void MapView::HandleAddCorner(void)
+{
+//printf("MapView::HandleAddCorner... (iTmp=%i, opInProgress=%i)\n", iTmp, opInProgress);
+ ASSERT(opInProgress == gmoAddCorner);
+ ASSERT(selectedOne >= 0);
+
+ int room = doc->addCorner(selectedOne, iTmp);
+
+ if (room >= 0)
+ selectOnlyRoom(room);
+// else
+// MessageBeep(MB_ICONASTERISK);
+
+ opInProgress = gmoNone;
+ update();
+}
+
+
+void MapView::HandleAddUnexplored(void)
+{
+ EdgeVec deletedEdges;
+ const bool wasModified = doc->isDirty;
+ MapEdge e;
+
+ edgeTmp.room1 = roomClicked;
+ edgeTmp.end1 = cornerClicked;
+ // This is from MapView::setEdgeType()
+ edgeTmp.type1 &= ~etSpecial;
+ edgeTmp.type1 |= etUnexplored;
+ edgeTmp.room2 = 0;
+ edgeTmp.end2 = rcSW;
+
+ // Look for an existing connection:
+// int eNum = doc->findEdge(selectedOne, cornerClicked, e);
+ int eNum = doc->findEdge(roomClicked, cornerClicked, e);
+
+ if (eNum >= 0)
+ {
+ deletedEdges.push_back(doc->edge[eNum]);
+ doc->deleteEdge(eNum);
+ }
+
+ doc->addEdge(edgeTmp);
+
+ if (deletedEdges.size())
+ doc->setUndoData(new UndoChangeEdge(wasModified, deletedEdges[0]));
+ else
+ doc->setUndoData(new UndoAdd(wasModified)); // Undo new edge
+
+ opInProgress = gmoNone;
+ update();
+}
+
+
+void MapView::HandleAddLoopBack(void)
+{
+ EdgeVec deletedEdges;
+ const bool wasModified = doc->isDirty;
+ MapEdge e;
+
+ edgeTmp.room1 = roomClicked;
+ edgeTmp.end1 = cornerClicked;
+ // This is from MapView::setEdgeType()
+ edgeTmp.type1 &= ~etSpecial;
+ edgeTmp.type1 |= etLoopBack;
+ edgeTmp.room2 = 0;
+ edgeTmp.end2 = rcSW;
+
+ // Look for an existing connection:
+// int eNum = doc->findEdge(selectedOne, cornerClicked, e);
+ int eNum = doc->findEdge(roomClicked, cornerClicked, e);
+
+ if (eNum >= 0)
+ {
+ deletedEdges.push_back(doc->edge[eNum]);
+ doc->deleteEdge(eNum);
+ }
+
+ doc->addEdge(edgeTmp);
+
+ if (deletedEdges.size())
+ doc->setUndoData(new UndoChangeEdge(wasModified, deletedEdges[0]));
+ else
+ doc->setUndoData(new UndoAdd(wasModified)); // Undo new edge
+
+ opInProgress = gmoNone;
+ update();
+}
+
+
+void MapView::HandleAddNoExit(void)
+{
+ EdgeVec deletedEdges;
+ const bool wasModified = doc->isDirty;
+ MapEdge e;
+
+ edgeTmp.room1 = roomClicked;
+ edgeTmp.end1 = cornerClicked;
+ // This is from MapView::setEdgeType()
+ edgeTmp.type1 &= ~etSpecial;
+ edgeTmp.type1 |= etNoExit;
+ edgeTmp.room2 = 0;
+ edgeTmp.end2 = rcSW;
+
+ // Look for an existing connection:
+// int eNum = doc->findEdge(selectedOne, cornerClicked, e);
+ int eNum = doc->findEdge(roomClicked, cornerClicked, e);
+
+ if (eNum >= 0)
+ {
+ deletedEdges.push_back(doc->edge[eNum]);
+ doc->deleteEdge(eNum);
+ }
+
+ doc->addEdge(edgeTmp);
+
+ if (deletedEdges.size())
+ doc->setUndoData(new UndoChangeEdge(wasModified, deletedEdges[0]));
+ else
+ doc->setUndoData(new UndoAdd(wasModified)); // Undo new edge
+
+ opInProgress = gmoNone;
+ update();
+}
+
+
+void MapView::SetEdgeDirection(EdgeType et)
+{
+ MapEdge e;
+
+ // Look for an existing connection:
+ int eNum = doc->findEdge(roomClicked, cornerClicked, e);
+
+ if (eNum >= 0)
+ {
+ // Is the room we clicked on room1 of this edge?
+ if (doc->edge[eNum].room1 == roomClicked)
+ {
+ doc->edge[eNum].type1 &= ~etDirection;
+ doc->edge[eNum].type1 |= et;
+ }
+ else
+ {
+ doc->edge[eNum].type2 &= ~etDirection;
+ doc->edge[eNum].type2 |= et;
+ }
+ }
+
+ opInProgress = gmoNone;
+ update();
+}
+
+
+void MapView::HandleAddUp(void)
+{
+ SetEdgeDirection(etUp);
+}
+
+
+void MapView::HandleAddDown(void)
+{
+ SetEdgeDirection(etDown);
+}
+
+
+void MapView::HandleAddIn(void)
+{
+ SetEdgeDirection(etIn);
+}
+
+
+void MapView::HandleAddOut(void)
+{
+ SetEdgeDirection(etOut);
+}
+
+
+void MapView::SetEdges(int room, int edgeNum, EdgeType eType)
+{
+/*
+OK, this is where the data structures let us down because they were poorly designed. Apparently, we have to walk thru the Edge vector for EVERY edge that has a corner to get to the other side. THIS LITERALLY FUCKING SUCKS.
+
+Algorithm:
+1) Figure out which side of the Edge has the room we're starting with.
+2) Using the other room # from the current Edge, loop thru the Edge vector to find the Edge connected to the room # we're looking at.
+3) Once the Edge is found, check to see if it's an rfCorner.
+ if so, go to 1)
+ else, we're done.
+
+Also, it seems that etOneWay only gets picked up by... type1. Which means, you have to swap the edge to get the arrowhead to point the other way...
+Which means you could do away with type2, only it uses that to distinguish the Up/Down/In/Out annotations put on map edges...
+Bleah.
+
+One way to make that less awful is to overload the RoomCorner (which, for some reason, already has I/O/U/D in it as distinct members) so that it has bitfields reserved for labels attached... Then EdgeType would really be an edge type and separate from the room exits.
+*/
+ // Go thru from current room to all connected "corner" rooms
+ while (true)
+ {
+ // Check for the unlikely case that we got passed bad info
+ if (doc->edge[edgeNum].HasRoom(room) == false)
+ break;
+
+ if (doc->edge[edgeNum].room2 == room)
+ doc->edge[edgeNum].Swap();
+
+ if (((eType == etOneWay) && (doc->edge[edgeNum].end2 != rcCorner))
+ || (eType != etOneWay))
+ doc->edge[edgeNum].type1 |= eType;
+
+ if (doc->edge[edgeNum].end2 != rcCorner)
+ return;
+
+ // Find next Edge... :-/
+ room = doc->edge[edgeNum].room2;
+
+ for(int i=0; i<doc->edge.size(); i++)
+ {
+ // Exclude the edge we just came from...
+ if (i == edgeNum)
+ continue;
+
+ if (doc->edge[i].HasRoom(room))
+ {
+ edgeNum = i;
+ break;
+ }
+ }
+ }
+}
+
+
+void MapView::ClearEdges(int room, int edgeNum, EdgeType eType)
+{
+ // Go thru from current room to all connected "corner" rooms
+ while (true)
+ {
+ // Check for the unlikely case that we got passed bad info
+ if (doc->edge[edgeNum].HasRoom(room) == false)
+ break;
+
+ if (doc->edge[edgeNum].room2 == room)
+ doc->edge[edgeNum].Swap();
+
+ doc->edge[edgeNum].type1 &= ~eType;
+
+ if (doc->edge[edgeNum].end2 != rcCorner)
+ return;
+
+ // Find next Edge... :-/
+ room = doc->edge[edgeNum].room2;
+
+ for(int i=0; i<doc->edge.size(); i++)
+ {
+ // Exclude the edge we just came from...
+ if (i == edgeNum)
+ continue;
+
+ if (doc->edge[i].HasRoom(room))
+ {
+ edgeNum = i;
+ break;
+ }
+ }
+ }
+}
+
+
+void MapView::HandleAddOneWay(void)
+{
+ MapEdge e;
+
+ // Look for an existing connection:
+ int eNum = doc->findEdge(roomClicked, cornerClicked, e);
+
+ if (eNum >= 0)
+ SetEdges(roomClicked, eNum, etOneWay);
+
+ opInProgress = gmoNone;
+ update();
+}
+
+
+void MapView::HandleClearOneWay(void)
+{
+ MapEdge e;
+
+ // Look for an existing connection:
+ int eNum = doc->findEdge(roomClicked, cornerClicked, e);
+
+ if (eNum >= 0)
+ ClearEdges(roomClicked, eNum, etOneWay);
+
+ opInProgress = gmoNone;
+ update();
+}
+
+
+void MapView::HandleAddRestricted(void)
+{
+ MapEdge e;
+
+ // Look for an existing connection:
+ int eNum = doc->findEdge(roomClicked, cornerClicked, e);
+
+ if (eNum >= 0)
+ SetEdges(roomClicked, eNum, etObstructed);
+
+ opInProgress = gmoNone;
+ update();
+}
+
+
+void MapView::HandleClearRestricted(void)
+{
+ MapEdge e;
+
+ // Look for an existing connection:
+ int eNum = doc->findEdge(roomClicked, cornerClicked, e);
+
+ if (eNum >= 0)
+ ClearEdges(roomClicked, eNum, etObstructed);
+
+ opInProgress = gmoNone;
+ update();
+}
+
+
+//void MapView::OnEditAddRoom()
+void MapView::HandleAddRoom(void)
+{
+ addRoom(scrollDragStart);
+}
+
+
+void MapView::HandleMapProperties(void)
+{
+ MapDialog dlg;
+
+ dlg.title.setText(doc->name.c_str());
+ dlg.comment.setPlainText(doc->note.c_str());
+ dlg.navMode.setChecked(doc->locked);
+ dlg.displayGrid.setChecked(showGrid);
+ dlg.showCorners.setChecked(showCorners);
+ dlg.showPages.setChecked(showPages);
+
+ if (dlg.exec() == false)
+ return;
+
+ doc->setName(dlg.title.text().toUtf8().data());
+ doc->setNote(dlg.comment.document()->toPlainText().toUtf8().data());
+ doc->locked = dlg.navMode.isChecked();
+ showGrid = dlg.displayGrid.isChecked();
+ showCorners = dlg.showCorners.isChecked();
+ showPages = dlg.showPages.isChecked();
+
+ if (dlg.title.text().isEmpty() == false)
+ setWindowTitle(dlg.title.text());
+
+ update();
+}
+
+
+//void MapView::OnEditClear()
+void MapView::HandleDelete(void)
+{
+ deleteSelection();
+ update();
+}
+
+
+#if 0
+//--------------------------------------------------------------------
+void MapView::OnEditAddPage()
+{
+ MapDoc * const doc = GetDocument();
+ ASSERT_VALID(doc);
+
+ const int p = doc->page.size();
+
+ if (p < maxPages)
+ {
+ MapPage page;
+ page.pos = scrollDragStart;
+ page.pos.x -= page.pos.x % gridX;
+ page.pos.y -= page.pos.y % gridY;
+ doc->setUndoData(new UndoAdd(doc->isDirty, p));
+ showPages = true;
+ doc->addPage(p, page);
+ clearSelection();
+ selectPage(p);
+ }
+}
+#endif
+
+
+//
+// Input:
+// removeCorner: (default true)
+// When TRUE, if a single corner is selected, remove it but leave
+// the connection. When FALSE, the connection is always removed.
+//
+void MapView::deleteSelection(bool removeCorner/* = true*/)
+{
+ if (numSelected || numSelectedPages)
+ {
+ if (doc->locked || (numSelectedPages == doc->page.size()))
+ {
+// MessageBeep(MB_ICONASTERISK);
+ return;
+ }
+
+ if (removeCorner && (selectedOne >= 0)
+ && doc->room[selectedOne].isCorner())
+ {
+ // Replace this corner with a single edge:
+ doc->deleteCorner(selectedOne);
+ clearSelection(false);
+ selectDone();
+ return;
+ }
+ else
+ {
+ // Select all corners if one corner or one end is selected:
+ const EdgeVec & edge = doc->edge;
+ int wereSelected = 0;
+
+ while (wereSelected != numSelected)
+ {
+ wereSelected = numSelected;
+
+ for(EdgeConstItr e=edge.begin(); e!=edge.end(); ++e)
+ {
+ if ((e->end1 == rcCorner) && selected[e->room2] && !selected[e->room1])
+ selectRoom(e->room1, false);
+ else if ((e->end2==rcCorner) && selected[e->room1] && !selected[e->room2])
+ selectRoom(e->room2, false);
+ }
+ }
+ }
+
+ UndoDelete * undoRec = new UndoDelete(*doc, numSelected, selected, numSelectedPages, selectedPage);
+ opInProgress = gmoDeleting; // Don't clear selection after first room
+ int pos = numSelected;
+
+ for(int i=doc->room.size()-1; i>=0; i--)
+ {
+ if (selected[i])
+ undoRec->addRoom(--pos, i, doc->extractRoom(i));
+ }
+
+ for(int i=doc->page.size()-1; i>=0; i--)
+ {
+ if (selectedPage[i])
+ doc->deletePage(i);
+ }
+
+ selectedPage.resize(doc->page.size(), 0);
+ opInProgress = gmoNone;
+ doc->setUndoData(undoRec);
+
+ clearSelection(false);
+ selectDone();
+ }
+}
+
+
+#if 0
+//--------------------------------------------------------------------
+// Cut, Copy & Paste:
+
+void MapView::OnEditCopy()
+{
+ if (numSelected || numSelectedPages)
+ {
+ MapDoc * doc = GetDocument();
+ ASSERT_VALID(doc);
+
+ // Deselect all corner rooms:
+ for(int i=doc->room.size()-1; i>=0; --i)
+ {
+ if (selected[i] && doc->room[i].isCorner())
+ deselectRoom(i);
+ }
+
+ if (!numSelected && !numSelectedPages)
+ {
+ selectDone();
+ MessageBeep(MB_ICONASTERISK);
+ return;
+ } // end if only corners were selected
+
+ // Select corners between selected rooms:
+ const EdgeVec& edges = doc->edge;
+
+ for (EdgeConstItr e = edges.begin(); e != edges.end(); ++e)
+ {
+ if ((selected[e->room1] && (e->end2 == rcCorner)
+ && (e->end1 != rcCorner) && !selected[e->room2])
+ || (selected[e->room2] && (e->end1 == rcCorner)
+ && (e->end2 != rcCorner) && !selected[e->room1]))
+ {
+ RoomNumVec cornerRooms;
+ cornerRooms.reserve(16); // Should be plenty
+ int otherEnd = doc->findOtherEnd(e, &cornerRooms);
+
+ if ((otherEnd >= 0) && selected[otherEnd])
+ {
+ for(RNConstItr rn=cornerRooms.begin(); rn!=cornerRooms.end(); ++rn)
+ selectRoom(*rn);
+ }
+ } // end if edge connects selected room to unselected corner
+ }
+
+ selectDone();
+
+ // Copy selected rooms and pages:
+ gueApp()->setClipboard(new RoomScrap(*doc, numSelected, selected, numSelectedPages, selectedPage));
+ }
+}
+
+
+void MapView::OnEditCut()
+{
+ OnEditCopy();
+ deleteSelection();
+}
+
+
+void MapView::OnEditPaste()
+{
+ const RoomScrap * scrap = static_cast<CMapApp *>(AfxGetApp())->getClipboard();
+
+ if (scrap)
+ {
+ MapDoc * doc = GetDocument();
+ ASSERT_VALID(doc);
+
+ int i = doc->room.size();
+
+ doc->setUndoData(scrap->paste(*doc));
+ const int numRooms = doc->room.size();
+
+ if (numRooms > i)
+ makeRoomVisible(i);
+
+ clearSelection(true);
+
+ while (i < numRooms)
+ selectRoom(i++, true);
+
+ selectDone();
+ }
+}
+
+
+void MapView::OnEditPaginate()
+{
+ showPages = true;
+ GetDocument()->layoutPages();
+}
+#endif
+
+
+//
+// Handle Edit Properties:
+//
+void MapView::HandleRoomProperties(void)
+{
+// editProperties((cmd == ID_EDIT_MAP_PROPERTIES) ? epuMapInfo : epuRoomInfo);
+ editProperties(epuRoomInfo);
+}
+
+
+//
+// Bring up the Properties dialog:
+//
+// Input:
+// undoType:
+// The type of action we should create an undo record for
+// epuRoomInfo: Just changing room info
+// epuAddRoom: Adding a new room
+// epuAddRoomEdge: Adding a new room and a new edge
+// wasModified:
+// The modification state of the document
+// (Necessary only if undoType is not epuRoomInfo)
+// edges: (default NULL)
+// A pointer to the edges that were deleted before adding this room
+// NULL if no edges were deleted
+// Must be NULL unless undoType is epuAddRoomEdge
+// The vector is emptied but not deleted
+//
+void MapView::editProperties(EditPropUndo undoType, bool wasModified/*= false*/, EdgeVec * edges/*= NULL*/)
+{
+ bool forceMap = false;
+
+ if (undoType == epuMapInfo)
+ {
+ undoType = epuRoomInfo;
+ forceMap = true;
+ }
+
+// CPropertySheet dlg(tr("Properties"));
+ RoomDialog dlg(this);
+// CRoomPropPage room;
+ UndoRoomInfo * undoRoom = NULL;
+ const bool roomTab = (selectedOne >= 0) && !doc->room[selectedOne].isCorner();
+
+// CMapPropPage map;
+// Strcpy(map.name, doc->getName());
+// Strcpy(map.note, doc->getNote());
+// map.corners = showCorners;
+// map.locked = doc->locked;
+// map.grid = showGrid;
+// map.pages = showPages;
+// dlg.AddPage(&map);
+
+// if (roomTab)
+ {
+// VERIFY(undoRoom = new UndoRoomInfo(*doc, selectedOne));
+ undoRoom = new UndoRoomInfo(*doc, selectedOne);
+// room.border = bool((undoRoom->getRoom().flags & rfBorder) != 0);
+// Strcpy(room.name, undoRoom->getRoom().name);
+// Strcpy(room.note, undoRoom->getRoom().note);
+// dlg.AddPage(&room);
+// static_cast<CMapApp *>(AfxGetApp())->setComment(this, NULL, false);
+ dlg.name.setText(undoRoom->room.name.c_str());
+ dlg.comment.insertPlainText(undoRoom->room.note.c_str());
+ dlg.border.setChecked(bool((undoRoom->room.flags & rfBorder) != 0));
+
+// if (!forceMap)
+// dlg.SetActivePage(&room);
+ }
+
+// if (dlg.DoModal() == IDOK)
+ if (dlg.exec())
+ {
+ if (roomTab)
+ {
+ bool changed = false;
+
+// if (room.border != (0 != (undoRoom->getRoom().flags & rfBorder)))
+ if (dlg.border.isChecked() != (0 != (undoRoom->room.flags & rfBorder)))
+ {
+// doc->setRoomFlags(selectedOne, (room.border ? rfBorder : 0), rfBorder);
+ doc->setRoomFlags(selectedOne, (dlg.border.isChecked() ? rfBorder : 0), rfBorder);
+ changed = true;
+ }
+
+// if (room.name != undoRoom->getRoom().name.c_str())
+ if (dlg.name.text().toUtf8().data() != undoRoom->room.name.c_str())
+ {
+// if (room.name.Find('\n') < 0)
+// wrapRoomName(room.name);
+
+ doc->setRoomName(selectedOne, dlg.name.text().toUtf8().data());
+ changed = true;
+ }
+
+// room.note.TrimRight();
+
+ if (dlg.comment.document()->toPlainText().toUtf8().data() != undoRoom->room.note.c_str())
+ {
+// doc->setRoomNote(selectedOne, room.note);
+ doc->setRoomNote(selectedOne, dlg.comment.document()->toPlainText().toUtf8().data());
+ changed = true;
+ }
+
+ if (changed && (undoType == epuRoomInfo))
+ {
+ doc->setUndoData(undoRoom);
+ undoRoom = NULL; // undoRoom now belongs to the document
+ }
+ }
+
+ if (undoType != epuRoomInfo)
+ {
+ ASSERT(selectedOne >= 0);
+
+ if (edges)
+ doc->setUndoData(new UndoChanges(wasModified, selectedOne, 1, *edges));
+ else
+ doc->setUndoData(new UndoAdd(wasModified, selectedOne, (undoType == epuAddRoomEdge ? 1 : 0)));
+ }
+
+// doc->setName(map.name);
+// doc->setNote(map.note);
+
+// if (doc->locked != bool(map.locked))
+// doc->OnNavigationMode();
+
+/* if ((showCorners != bool(map.corners))
+ || (showGrid != bool(map.grid))
+ || (showPages != bool(map.pages)))
+ {
+ showCorners = map.corners != 0;
+ showGrid = map.grid != 0;
+ showPages = map.pages != 0;
+
+ if (!showPages)
+ deselectPages(false);
+
+// InvalidateRect(NULL);
+ }*/
+ }
+ else if (undoType != epuRoomInfo)
+ {
+ // Cancel adding the room:
+ ASSERT(selectedOne >= 0);
+ const RoomNum roomNum = selectedOne;
+ clearSelection();
+
+ if (undoType == epuAddRoomEdge)
+ {
+ const MapEdge & edge = doc->edge[doc->edge.size() - 1];
+ selectOnlyRoom(edge.room1 == roomNum ? edge.room2 : edge.room1);
+ }
+
+ opInProgress = gmoDeleting; // Don't clear selection
+ doc->deleteRoom(roomNum);
+ opInProgress = gmoNone;
+
+ if (edges)
+ {
+ doc->addEdges(edges->size());
+
+ for(EdgeConstItr e=edges->begin(); e!=edges->end(); e++)
+ doc->addEdge(*e);
+ }
+
+ doc->isDirty = wasModified;
+ }
+
+ selectDone();
+ update();
+ delete undoRoom;
+}
+
+
+#if 0
+//
+// Select all rooms:
+//
+void MapView::OnEditSelectAll()
+{
+ for(int i=doc->room.size()-1; i>=0; i--)
+ selectRoom(i);
+
+ selectDone();
+}
+
+
+//---------------------------------------------------------------------------
+// Select connected rooms:
+
+void MapView::OnEditSelectConnected()
+{
+ const MapDoc * doc = GetDocument();
+ ASSERT_VALID(doc);
+
+ const int numEdges = doc->getEdgeCount();
+ const EdgeVec & edge = doc->edge;
+
+ int wasSelected = 0;
+
+ while (wasSelected != numSelected)
+ {
+ wasSelected = numSelected;
+
+ for(int i=0; i<numEdges; i++)
+ {
+ if ((edge[i].type1 & etNoRoom2) == 0)
+ {
+ if (selected[edge[i].room1])
+ selectRoom(edge[i].room2);
+ else if (selected[edge[i].room2])
+ selectRoom(edge[i].room1);
+ } // end if edge connects two rooms
+ }
+ } // end while more rooms were selected on this pass
+
+ selectDone();
+}
+
+
+void MapView::OnInitialUpdate()
+{
+ const MapDoc * doc = GetDocument();
+ ASSERT_VALID(doc);
+
+ selectedPage.resize(doc->page.size(), 0);
+ clearSelection(false);
+
+ // Set the document size:
+ init(4 * gridX, doc->getDocSize(), QSize(gridX, gridY));
+// CClientDC dc(this);
+// OnPrepareDC(&dc);
+ LOGFONT lf;
+ memset(&lf, 0, sizeof(lf));
+ lf.lfHeight = 62;
+ strcpy(lf.lfFaceName, "Arial");
+ font.CreateFontIndirect(&lf);
+
+ if (doc->locked)
+ OnUpdate(NULL, dupNavigationMode, NULL);
+
+ CScrollZoomView::OnInitialUpdate();
+ setScrollBars(); // Now fix the scroll bars
+}
+
+
+void MapView::OnKeyDown(unsigned int c, unsigned int nRepCnt, unsigned int nFlags)
+{
+ bool ctrl = (GetKeyState(VK_CONTROL) < 0);
+
+ switch (c)
+ {
+ case VK_LEFT: OnHScroll(ctrl ? SB_PAGELEFT : SB_LINELEFT, 0, NULL); break;
+ case VK_RIGHT: OnHScroll(ctrl ? SB_PAGERIGHT : SB_LINERIGHT, 0, NULL); break;
+ case VK_UP: OnVScroll(ctrl ? SB_PAGEUP : SB_LINEUP, 0, NULL); break;
+ case VK_DOWN: OnVScroll(ctrl ? SB_PAGEDOWN : SB_LINEDOWN, 0, NULL); break;
+ case VK_PRIOR: OnVScroll(ctrl ? SBtrOP : SB_PAGEUP, 0, NULL); break;
+ case VK_NEXT: OnVScroll(ctrl ? SB_BOTTOM : SB_PAGEDOWN, 0, NULL); break;
+ case VKtrAB: gueApp()->editComment(); break;
+ default:
+ if ((GetKeyState(VK_SHIFT) >= 0) && (c >= '0') && (c <= '9'))
+ {
+ if (!ctrl && (c < '2'))
+ zoomTo(100);
+ else if (ctrl && (c == '0'))
+ zoomTo(200);
+ else
+ zoomTo(10 * (c - '0') + (ctrl ? 100 : 0));
+ } // end if number key (not shifted)
+
+ break;
+ }
+}
+#endif
+
+
+void MapView::mouseDoubleClickEvent(QMouseEvent * event)
+//void MapView::OnLButtonDblClk(unsigned int nFlags, QPoint point)
+{
+ if (scrollDrag || scrollDragTimer)
+ return;
+
+// QPoint point = event->pos() * 5;
+ QPointF ptf = event->localPos() * (100.0 / zoom);
+ QPoint point = ptf.toPoint();
+// QPoint point = event->pos() * (100.0 / zoom);
+ int nFlags = event->modifiers();
+
+ // Scroll support
+ point -= offset;
+
+ opInProgress = gmoNone;
+
+// if (GetCapture() == this)
+// ReleaseCapture();
+
+// CClientDC dc(this);
+// OnPrepareDC(&dc);
+// dc.DPtoLP(&point);
+
+ const int i = doc->roomHit(point);
+//printf("MapView::mouseDoubleClickEvent: roomHit=%i\n", i);
+
+ if ((i >= 0) && (doc->room[i].isCorner() == false))
+ {
+ selectOnlyRoom(i);
+ editProperties(epuRoomInfo);
+ }
+ else if (i < 0)
+ addRoom(point);
+}
+
+
+/* N.B.: Handles RButton & MButton too */
+void MapView::mousePressEvent(QMouseEvent * event)
+//void MapView::OnLButtonDown(unsigned int nFlags, QPoint point)
+/*
+nFlags = MK_CONTROL, MK_SHIFT, MK_{LMR}BUTTON
+*/
+{
+ // We need to adjust the position to take into account the scale factor, which in this case, is 1/5:
+// QPoint point = event->pos() * 5;
+ QPointF ptf = event->localPos() * (100.0 / zoom);
+ QPoint point = ptf.toPoint();
+// QPoint point = event->pos() * (100 / zoom);
+ int nFlags = event->modifiers();
+ mouseDown = true;//will prolly have to separate this out to L, M & R :-P
+/*
+Qt::NoModifier, Qt::ShiftModifier, Qt::ControlModifier, Qt::AltModifier, etc.
+*/
+
+ // Scrolling support (save this for now)...
+ point -= offset;
+ offsetScrollDragStart = offset;
+ scrollDragStart = point + offset;
+
+ if (event->button() == Qt::LeftButton)
+ {
+ if (scrollDrag || scrollDragTimer)
+ return;
+
+// CClientDC dc(this);
+// OnPrepareDC(&dc);
+// dc.DPtoLP(&point);
+
+ RoomCorner corner;
+ int room = doc->roomHit(point, &corner);
+
+ if (room < 0)
+ {
+ if (doc->locked)
+ return; // Must have 1 room selected during navigation
+
+ if (showPages && ((room = doc->pageBorderHit(point)) >= 0))
+ {
+ iTmp = room;
+
+// if (nFlags & MK_CONTROL)
+ if (nFlags & Qt::ControlModifier)
+ {
+ opInProgress = gmoControlDown;
+ bTmp = selectedPage[room];
+ b2Tmp = true; // In page
+ }
+ else
+ {
+// if (nFlags & MK_SHIFT)
+ if (nFlags & Qt::ShiftModifier)
+ opInProgress = gmoShiftDown;
+ else
+ opInProgress = gmoNone;
+
+ clearSelection();
+ }
+
+ selectPage(room);
+ selectDone();
+
+ if (opInProgress)
+ {
+// SetCapture();
+ p1Tmp.rx() = point.x() / gridX;
+ p1Tmp.ry() = point.y() / gridY;
+ p2Tmp = doc->page[room].pos;
+ }
+ }
+ else
+ {
+// SetCapture();
+ opInProgress = gmoSelectBox;
+
+// if (nFlags & MK_CONTROL)
+ if (nFlags & Qt::ControlModifier)
+ {
+ // If Ctrl pressed, don't clear selection:
+ for(ByteItr b=selected.begin(); b!=selected.end(); b++)
+ {
+ if (*b)
+ *b = 2; // Mark the rooms that should stay selected
+ }
+
+ for(ByteItr b=selectedPage.begin(); b!=selectedPage.end(); b++)
+ {
+ if (*b)
+ *b = 2; // Mark the pages that should stay selected
+ }
+ }
+ else
+ {
+ clearSelection();
+ selectDone();
+ }
+
+ p1Tmp = point;
+ p2Tmp = point;
+// rTmp.left = rTmp.right = point.x;
+// rTmp.bottom = rTmp.top = point.y;
+ rTmp.setCoords(point.x(), point.y(), point.x(), point.y());
+ }
+
+ update();
+ }
+ else if (doc->locked)
+ {
+#if 0
+ ASSERT(selectedOne >= 0);
+
+ if ((room != selectedOne) && !doc->room[room].isCorner())
+ {
+ String path;
+ doc->shortestPath(path, selectedOne, room);
+
+ if (path.empty())
+ path = tr("Sorry, I don't know how to get there.");
+ else if (path.find('.') != String::npos)
+ {
+ const CMapApp * app = static_cast<CMapApp *>(AfxGetApp());
+
+ if (app->navigationCopy())
+ {
+ if (app->navigationCRLF())
+ path += tr("\r\n");
+
+ pasteClipboard(path);
+ }
+ }
+ // end else if path has multiple steps
+
+ static_cast<CMainFrame *>(AfxGetMainWnd())->setStatusBar(path.c_str());
+ selectOnlyRoom(room);
+ }
+ // end if moving to new room in navigation mode
+#endif
+ }
+// else if (nFlags & MK_CONTROL)
+ else if (nFlags & Qt::ControlModifier)
+ {
+// SetCapture();
+ opInProgress = gmoControlDown;
+ ASSERT(room < selected.size());
+ bTmp = selected[room];
+ b2Tmp = false; // In room
+ iTmp = room;
+ selectRoom(room);
+ selectDone();
+ p1Tmp.rx() = point.x() / gridX;
+ p1Tmp.ry() = point.y() / gridY;
+ update();
+ }
+// else if (nFlags & MK_SHIFT)
+ else if (nFlags & Qt::ShiftModifier)
+ {
+// SetCapture();
+ opInProgress = gmoShiftDown;
+ selectOnlyRoom(room);
+ iTmp = -1; // Not a page
+ p1Tmp.rx() = point.x() / gridX;
+ p1Tmp.ry() = point.y() / gridY;
+ p2Tmp = doc->room[room].pos;
+ }
+ else
+ {
+ selectOnlyRoom(room);
+
+ if (!(doc->room[room].isCorner()))
+ emit(RoomClicked(doc, room));
+
+ if (doc->room[room].isCorner())
+ {
+// SetCapture();
+ opInProgress = gmoControlDown;
+ bTmp = b2Tmp = false; // Leave the corner selected; in room
+ p1Tmp.rx() = point.x() / gridX;
+ p1Tmp.ry() = point.y() / gridY;
+ }
+ else if (corner != rcNone)
+ {
+// SetCapture();
+ opInProgress = gmoAddEdge;
+ bTmp = doc->isDirty;
+ iTmp = doc->findEdge(room, corner, edgeTmp);
+
+ if (iTmp >= 0)
+ {
+ opInProgress = gmoChangeEdge;
+ rTmp.setCoords(point.x() - 29, point.y() - 29, point.x() + 29, point.y() + 29);
+// rTmp.InflateRect(29, 29);
+ }
+
+ if ((iTmp < 0) || (edgeTmp.type2 & etNoRoom2))
+ {
+ edgeTmp.room1 = room;
+ edgeTmp.end1 = corner;
+ setEdgeType(edgeTmp);
+ }
+
+ edgeTmp.room2 = 0;
+ edgeTmp.end2 = rcSW;
+ doc->getEdgePoints(edgeTmp, p1Tmp, p2Tmp);
+
+ p2Tmp = p1Tmp;
+// OnPaint(); // Update the view immediately
+
+#if 0
+ if (opInProgress == gmoAddEdge)
+ {
+ dc.SetROP2(R2_NOT);
+ QPen penEdge;
+
+ if (!penEdge.CreatePen(PS_SOLID, penEdgeWidth, RGB(0, 0, 0)))
+ return;
+
+ QPen * oldPen = dc.SelectObject(&penEdge);
+ dc.MoveTo(p1Tmp);
+ dc.LineTo(p2Tmp);
+ dc.SelectObject(oldPen);
+ }
+#endif
+ }
+
+ update();
+ }
+ }
+ else if (event->button() == Qt::RightButton)
+ {
+//void MapView::OnRButtonDown(unsigned int nFlags, QPoint point)
+//{
+/* if (opInProgress == gmoAddCorner)
+ opInProgress = gmoNone;
+
+// CClientDC dc(this);
+// OnPrepareDC(&dc);
+// dc.DPtoLP(&point);
+
+ scrollDragStart = point;
+
+ if (opInProgress)
+ {
+// SetCapture();
+ scrollDrag = true;
+// ::SetCursor(handCursor);
+ }//*/
+// else
+// scrollDragTimer = SetTimer(menuTimer, clickTicks, NULL);
+//}
+ }
+}
+
+#if 0
+// From scrollzoom
+bool MapView::calcScrollPosition(QPoint & pt) const
+{
+ if (pt.x() < 0)
+ pt.rx() = 0;
+
+// if (pt.y() > 0)
+ if (pt.y() < 0)
+ pt.ry() = 0;
+
+// SCROLLINFO si;
+// VERIFY(const_cast<CScrollZoomView *>(this)->GetScrollInfo(SB_HORZ, &si, SIF_PAGE | SIF_POS | SIF_RANGE));
+
+// if (pt.x + si.nPage > si.nMax + scrollStep.cx)
+// pt.x = si.nMax - si.nPage + scrollStep.cx;
+
+// VERIFY(const_cast<CScrollZoomView *>(this)->GetScrollInfo(SB_VERT, &si, SIF_PAGE | SIF_POS | SIF_RANGE));
+
+// if (-pt.y + si.nPage > si.nMax + scrollStep.cy)
+// pt.y = si.nPage - si.nMax - scrollStep.cy;
+
+// pt.x -= pt.x % scrollStep.cx;
+// pt.y -= pt.y % scrollStep.cy;
+
+ return offset != pt;
+}
+
+
+// From scrollzoom
+void MapView::scrollToPosition(const QPoint & pt)
+{
+ QPoint newOffset(pt);
+
+ if (!calcScrollPosition(newOffset))
+ return; // Didn't scroll
+
+// QSize delta(newOffset - offset);
+ offset = newOffset;
+
+// CClientDC dc(this);
+// OnPrepareDC(&dc);
+// dc.LPtoDP(&delta);
+
+// SetScrollPos(SB_VERT, -offset.y);
+// SetScrollPos(SB_HORZ, offset.x);
+// ScrollWindow(-delta.cx, delta.cy);
+}
+#endif
+
+void MapView::mouseMoveEvent(QMouseEvent * event)
+//void MapView::OnMouseMove(unsigned int nFlags, QPoint point)
+{
+ // We need to adjust the position to take into account the scale factor, which in this case, is 1/5:
+// QPoint point = event->pos() * 5;
+ QPointF ptf = event->localPos() * (100.0 / zoom);
+ QPoint point = ptf.toPoint();
+// QPoint point = event->pos() * (100 / zoom);
+ int nFlags = event->modifiers();
+
+ // Scroll support
+ point -= offset;
+
+ // Location where the mouse is currently pointing
+ mouse = point;
+
+ // Bail if we're just mousing around...
+ if (mouseDown == false)
+ {
+ hoveredEdge = FindHoveredEdge();
+
+ update();
+ return;
+ }
+
+/* if (scrollDragTimer)
+ {
+// KillTimer(scrollDragTimer);
+ scrollDragTimer = 0;
+// SetCapture();
+ scrollDrag = true;
+// ::SetCursor(handCursor);
+ }//*/
+
+// if (GetCapture() != this)
+// return;
+
+// CClientDC dc(this);
+// OnPrepareDC(&dc);
+// dc.DPtoLP(&point);
+
+ if (scrollDrag)
+ {
+#if 0
+// MSG msg;
+ QPoint p(offset);
+// p.Offset(scrollDragStart - point);
+ p += (scrollDragStart - point);
+
+ if (!calcScrollPosition(p)
+)// || PeekMessage(&msg, m_hWnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE))
+ return;
+
+ if ((opInProgress == gmoAddEdge) || (opInProgress == gmoSelectBox)
+ || (opInProgress >= gmoDrag))
+ {
+#if 0
+ // We must handle these specially to avoid display artifacts:
+ dc.SetROP2(R2_NOT);
+ CGdiObject * old = NULL;
+ QPen pen;
+ QBrush brush;
+
+ switch (opInProgress)
+ {
+ case gmoAddEdge:
+ if (!pen.CreatePen(PS_SOLID, penEdgeWidth, RGB(0, 0 ,0)))
+ return;
+
+ old = dc.SelectObject(&pen);
+ dc.MoveTo(p1Tmp);
+ dc.LineTo(p2Tmp);
+ break;
+
+ case gmoSelectBox:
+ old = dc.SelectStockObject(HOLLOW_BRUSH);
+ dc.Rectangle(rTmp);
+ break;
+
+ default:
+ drawSelected(&dc);
+ break; // Must be gmoDrag
+ }
+#endif
+
+ scrollToPosition(p);
+// OnPaint();
+// OnPrepareDC(&dc); // Update with new offset
+
+#if 0
+ switch (opInProgress)
+ {
+ case gmoAddEdge: dc.MoveTo(p1Tmp); dc.LineTo(p2Tmp); break;
+ case gmoSelectBox: dc.Rectangle(rTmp); break;
+ default: /* drag*/ drawSelected(&dc); break;
+ }
+
+ if (old)
+ dc.SelectObject(old);
+#endif
+ }
+ else
+ scrollToPosition(p);
+#endif
+ QPoint delta = (point + offset) - scrollDragStart;
+ offset = offsetScrollDragStart + delta;
+ update();
+
+ return;
+ }
+
+ if (opInProgress == gmoChangeEdge)
+ {
+// if (rTmp.PtInRect(point))
+ if (rTmp.contains(point))
+ return;
+
+// e2Tmp = doc->getEdge(iTmp); // Save the current edge data
+ e2Tmp = doc->edge[iTmp]; // Save the current edge data
+ doc->deleteEdge(iTmp); // Delete the old edge
+// OnPaint(); // Update the view immediately
+ opInProgress = gmoAddEdge; // Now fall through to gmoAddEdge
+ }
+
+ if (opInProgress == gmoAddEdge)
+ {
+// dc.SetROP2(R2_NOT);
+// QPen penEdge;
+
+// if (!penEdge.CreatePen(PS_SOLID, penEdgeWidth, RGB(0, 0, 0))) // PORT
+// return;
+
+// QPen * oldPen = dc.SelectObject(&penEdge);
+// dc.MoveTo(p1Tmp);
+// dc.LineTo(p2Tmp);
+
+ RoomCorner corner;
+ int room = doc->roomHit(point, &corner);
+
+ if (corner != rcNone && room != edgeTmp.room1)
+ {
+ edgeTmp.room2 = room;
+ edgeTmp.end2 = corner;
+ doc->getEdgePoints(edgeTmp, p1Tmp, p2Tmp);
+ }
+ else
+ {
+ p2Tmp = point;
+ }
+
+// dc.MoveTo(p1Tmp);
+// dc.LineTo(p2Tmp);
+// dc.SelectObject(oldPen);
+ }
+ else if (opInProgress == gmoSelectBox)
+ {
+ if (p2Tmp != point)
+ {
+ p2Tmp = point;
+// dc.SetROP2(R2_NOT);
+// QBrush * oldBrush = static_cast<QBrush *>(dc.SelectStockObject(HOLLOW_BRUSH));
+// dc.Rectangle(rTmp);
+
+ rTmp = QRect(p1Tmp, point).normalized();
+// rTmp.NormalizeRect();
+ RoomConstItr room = doc->room.getVector().begin();
+// QRect intersect, r;
+
+ for(int i=doc->room.size()-1; i>=0; i--)
+ {
+ if (selected[i] == 2)
+ continue; // Room was already selected before selection box
+
+#if 0
+ room[i]->getRect(r);
+// intersect.IntersectRect(rTmp, r);
+ intersect = rTmp & r;
+#else
+ QRect r = room[i]->getRect();
+ QRect intersect = rTmp & r;
+#endif
+
+ if ((selected[i] != 0) != bool(r == intersect))
+ {
+ selected[i] = !selected[i];
+ numSelected += (selected[i] ? 1 : -1);
+// r.DeflateRect(5, 5);
+// dc.LPtoDP(&r);
+// r.NormalizeRect();
+// InvalidateRect(&r);
+ }
+ }
+
+ if (showPages)
+ {
+ for(int i=doc->page.size()-1; i>=0; i--)
+ {
+ if (selectedPage[i] == 2)
+ continue; // Page was already selected before selection box
+
+#if 0
+ doc->getPageRect(i, r);
+// intersect.IntersectRect(rTmp, r);
+ intersect = rTmp & r;
+#else
+ QRect r = doc->getPageRect(i);
+ QRect intersect = rTmp & r;
+#endif
+
+ if ((selectedPage[i] != 0) != bool(r == intersect))
+ {
+ selectedPage[i] = !selectedPage[i];
+ numSelectedPages += (selectedPage[i] ? 1 : -1);
+// r.DeflateRect(5, 5);
+// dc.LPtoDP(&r);
+// r.NormalizeRect();
+// InvalidateRect(&r);
+ }
+ }
+ }
+
+ if ((numSelected == 1) && !numSelectedPages)
+ {
+ for(selectedOne=0; !selected[selectedOne]; selectedOne++)
+ ; // Find the selected room
+ }
+ else
+ selectedOne = -1;
+
+ selectDone();
+
+// if (GetUpdateRect(NULL))
+// OnPaint();
+
+// dc.Rectangle(rTmp);
+// dc.SelectObject(oldBrush);
+ }
+ }
+ else if (opInProgress == gmoControlDown)
+ {
+ p2Tmp.rx() = gridX * (point.x() / gridX - p1Tmp.x());
+ p2Tmp.ry() = gridY * (point.y() / gridY - p1Tmp.y());
+
+ if (p2Tmp.x() || p2Tmp.y())
+ {
+ opInProgress = gmoControlDrag;
+ computeSelectedRect(rTmp);
+// drawBackground(&dc);
+// dc.SetROP2(R2_NOT);
+// drawSelected(&dc);
+ }
+ }
+ else if (opInProgress == gmoShiftDown)
+ {
+ long ox = point.x() / gridX;
+ long oy = point.y() / gridY;
+
+ if (ox < p1Tmp.x())
+ opInProgress = gmoShiftDragLeft;
+ else if (ox > p1Tmp.x())
+ opInProgress = gmoShiftDragRight;
+ else if (oy > p1Tmp.y())
+ opInProgress = gmoShiftDragUp;
+ else if (oy < p1Tmp.y())
+ opInProgress = gmoShiftDragDown;
+ else
+ return;
+
+ // if dragging a page
+ if (iTmp >= 0)
+ {
+ ASSERT(!numSelected && (numSelectedPages == 1));
+ rTmp = doc->getPageRect(iTmp);
+
+ switch (opInProgress)
+ {
+ case gmoShiftDragUp:
+ p2Tmp.ry() = rTmp.top();
+ break;
+ case gmoShiftDragLeft:
+ p2Tmp.rx() = rTmp.right() - roomWidth + gridX;
+ break;
+ }
+ }
+
+ RoomConstItr room = doc->room.getVector().begin();
+ const int roomCount = doc->room.size();
+
+ for(int i=0; i<roomCount; i++)
+ {
+ if ((opInProgress == gmoShiftDragLeft && room[i]->pos.x() <= p2Tmp.x())
+ || (opInProgress == gmoShiftDragRight && room[i]->pos.x() >= p2Tmp.x())
+ || (opInProgress == gmoShiftDragUp && room[i]->pos.y() >= p2Tmp.y())
+ || (opInProgress == gmoShiftDragDown && room[i]->pos.y() <= p2Tmp.y()))
+ selectRoom(i, false);
+
+ if (iTmp < 0)
+ {
+ // shift-dragging a room
+ if (opInProgress == gmoShiftDragLeft)
+ p2Tmp.rx() += roomWidth;
+ else if (opInProgress == gmoShiftDragDown)
+ p2Tmp.ry() += roomHeight;
+ }
+ else
+ {
+ // shift-dragging a page
+ if (opInProgress == gmoShiftDragLeft)
+ p2Tmp.rx() += gridX;
+ else if (opInProgress == gmoShiftDragRight)
+ p2Tmp.rx() -= gridX;
+ else if (opInProgress == gmoShiftDragUp)
+ p2Tmp.ry() -= gridY;
+ else if (opInProgress == gmoShiftDragDown)
+ p2Tmp.ry() += gridY;
+ }
+
+ for(i=doc->page.size()-1; i>=0; --i)
+ {
+ rTmp = doc->getPageRect(i);
+
+ if ((opInProgress == gmoShiftDragLeft && rTmp.right() < p2Tmp.x())
+ || (opInProgress == gmoShiftDragRight && rTmp.left() > p2Tmp.x())
+ || (opInProgress == gmoShiftDragUp && rTmp.top() > p2Tmp.y())
+ || (opInProgress == gmoShiftDragDown && rTmp.bottom() < p2Tmp.y()))
+ selectPage(i, false);
+ }
+ }
+
+ selectDone();
+
+ p2Tmp.rx() = gridX * (point.x() / gridX - p1Tmp.x());
+ p2Tmp.ry() = gridY * (point.y() / gridY - p1Tmp.y());
+ computeSelectedRect(rTmp);
+// drawBackground(&dc);
+// dc.SetROP2(R2_NOT);
+// drawSelected(&dc);
+ }
+ // end else if gmoShiftDown
+ else if (opInProgress >= gmoDrag)
+ {
+// MSG msg;
+
+// if (PeekMessage(&msg, m_hWnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE))
+// return; // The mouse has already been moved again
+
+ QPoint p(gridX * (point.x() / gridX - p1Tmp.x()), gridY * (point.y() / gridY - p1Tmp.y()));
+
+ if (p != p2Tmp)
+ {
+ adjustOffset(p);
+
+ if (p == p2Tmp)
+ return;
+
+// dc.SetROP2(R2_NOT);
+// drawSelected(&dc);
+ p2Tmp = p;
+// drawSelected(&dc);
+ }
+ }
+
+ // Maybe have more discriminant updating... Maybe.
+ update();
+}
+
+
+//void MapView::OnLButtonUp(unsigned int nFlags, QPoint point)
+void MapView::mouseReleaseEvent(QMouseEvent * event)
+{
+ // We need to adjust the position to take into account the scale factor, which in this case, is 1/5:
+// QPoint point = event->pos() * 5;
+ QPointF ptf = event->localPos() * (100.0 / zoom);
+ QPoint point = ptf.toPoint();
+// QPoint point = event->pos() * (100 / zoom);
+ int nFlags = event->modifiers();
+ mouseDown = false;
+
+ // Scroll support
+ point -= offset;
+
+ if (event->button() == Qt::LeftButton)
+ {
+ // if (GetCapture() != this)
+ // {
+ // if (selectedOne >= 0)
+ // makeRoomVisible(selectedOne);
+ //
+ // return;
+ // }
+
+ // if (!scrollDrag)
+ // ReleaseCapture();
+
+ // CClientDC dc(this);
+ // OnPrepareDC(&dc);
+ // dc.DPtoLP(&point);
+
+ if (opInProgress == gmoAddEdge)
+ {
+ // Erase the rubber band:
+ // dc.SetROP2(R2_NOT);
+ // QPen penEdge;
+
+ // if (!penEdge.CreatePen(PS_SOLID, penEdgeWidth, RGB(0, 0, 0)))
+ // return;
+
+ // QPen * oldPen = dc.SelectObject(&penEdge);
+ // dc.MoveTo(p1Tmp);
+ // dc.LineTo(p2Tmp);
+ // dc.SelectObject(oldPen);
+
+ // Find out where the edge goes:
+ RoomCorner corner;
+ int room = doc->roomHit(point, &corner);
+
+ if (corner != rcNone && room != edgeTmp.room1)
+ {
+ // The edge goes somewhere
+ // If there's a stub on the other end, delete it:
+ EdgeVec deletedEdges;
+ MapEdge oldEdge;
+ int oldEdgeNum = doc->findEdge(room, corner, oldEdge);
+
+ if (oldEdgeNum >= 0 && (oldEdge.type2 & etUnexplored))
+ {
+ // deletedEdges.push_back(doc->getEdge(oldEdgeNum));
+ deletedEdges.push_back(doc->edge[oldEdgeNum]);
+ doc->deleteEdge(oldEdgeNum);
+ }
+
+ // Add the new or changed edge:
+ if (edgeTmp.type2 & etOneWay)
+ {
+ edgeTmp.room2 = edgeTmp.room1;
+ edgeTmp.end2 = edgeTmp.end1;
+ edgeTmp.type1 = edgeTmp.type2 | (edgeTmp.type1 & etObstructed);
+ edgeTmp.type2 = etNormal;
+ edgeTmp.room1 = room;
+ edgeTmp.end1 = corner;
+ }
+ else
+ {
+ edgeTmp.room2 = room;
+ edgeTmp.end2 = corner;
+ }
+
+ if (iTmp >= 0)
+ deletedEdges.push_back(e2Tmp);
+
+ if (deletedEdges.size())
+ {
+ if (deletedEdges.size() == 1)
+ doc->setUndoData(new UndoChangeEdge(bTmp, deletedEdges[0]));
+ else
+ doc->setUndoData(new UndoChanges(bTmp, -1, 1, deletedEdges));
+ }
+ else
+ doc->setUndoData(new UndoAdd(bTmp));
+
+ doc->addEdge(edgeTmp);
+ }
+ else
+ {
+ if (iTmp >= 0)
+ {
+ // We just deleted the old edge
+ if ((e2Tmp.end1 == rcCorner)
+ || (!(e2Tmp.type1 & etNoRoom2) && (e2Tmp.end2 == rcCorner)))
+ {
+ doc->addEdge(e2Tmp); // Put it back temporarily
+ selectOnlyRoom((e2Tmp.end1 == rcCorner) ? e2Tmp.room1 : e2Tmp.room2);
+ deleteSelection(false); // Remove entire connection
+ }
+ else
+ // not a connection to a corner
+ doc->setUndoData(new UndoDelete(bTmp, e2Tmp));
+ }
+ else if (selectedOne >= 0)
+ makeRoomVisible(selectedOne); // We just clicked on a room corner
+ }
+ // end if edge doesn't go anywhere
+ }
+ else if (opInProgress == gmoChangeEdge)
+ {
+ // We didn't change the edge
+ if (selectedOne >= 0)
+ makeRoomVisible(selectedOne);
+ }
+ // else if (opInProgress == gmoSelectBox)
+ // {
+ // dc.SetROP2(R2_NOT);
+ // QBrush * oldBrush = static_cast<QBrush *>(dc.SelectStockObject(HOLLOW_BRUSH));
+ // dc.Rectangle(rTmp);
+ // dc.SelectObject(oldBrush);
+ // }
+ else if (opInProgress == gmoControlDown)
+ {
+ if (bTmp)
+ {
+ if (b2Tmp)
+ deselectPage(iTmp);
+ else
+ deselectRoom(iTmp);
+
+ selectDone();
+ }
+ // end if room or page was already selected
+ }
+ else if (opInProgress >= gmoDrag)
+ {
+ QPoint p(gridX * (point.x() / gridX - p1Tmp.x()), gridY * (point.y() / gridY - p1Tmp.y()));
+ adjustOffset(p);
+
+ if (p.x() || p.y())
+ {
+ const QSize offset1(p.x(), p.y());
+ doc->setUndoData(new UndoMove(doc->isDirty, offset1, numSelected, selected, numSelectedPages, selectedPage));
+
+ for(int i=doc->room.size()-1; i>=0; i--)
+ {
+ if (selected[i])
+ doc->moveRoom(i, offset1);
+ }
+
+ for(int i=doc->page.size()-1; i>=0; i--)
+ {
+ if (selectedPage[i])
+ doc->movePage(i, offset1);
+ }
+ }
+ // else
+ // InvalidateRect(NULL);
+ }
+
+ opInProgress = gmoNone;
+ }
+ else if (event->button() == Qt::RightButton)
+ {
+//void MapView::OnRButtonUp(unsigned int nFlags, QPoint point)
+//{
+// if (scrollDragTimer)
+ if (true)
+ {
+ // KillTimer(scrollDragTimer);
+ scrollDragTimer = 0;
+
+ RoomCorner corner;
+ int room = doc->roomHit(point, &corner);
+ cornerClicked = corner; // Bleah
+ roomClicked = room; // Bleah
+
+ if (room < 0)
+ {
+ if (showPages && (room = doc->pageBorderHit(point)) >= 0)
+ {
+ clearSelection();
+ selectPage(room);
+ selectDone();
+ }
+
+ mapContextMenu->popup(mapToGlobal(event->pos()));
+ }
+ else
+ {
+ selectOnlyRoom(room);
+ opInProgress = gmoNone;
+
+ if ((corner != rcNone) && !doc->locked)
+ {
+ iTmp = doc->findEdge(room, corner, edgeTmp);
+
+ if ((iTmp >= 0) && !(edgeTmp.type2 & etNoRoom2))
+ {
+ opInProgress = gmoAddCorner;
+ addCornerAct->setEnabled(true);
+ }
+ else
+ addCornerAct->setEnabled(false);
+ }
+
+ roomContextMenu->popup(mapToGlobal(event->pos()));
+ mouse = QPoint(0, 0);
+ }
+
+ // dc.LPtoDP(&point);
+ // ClientToScreen(&point);
+ // pop->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, AfxGetMainWnd());
+ // //opInProgress = gmoNone; // FIXME
+ }
+ // else if (!scrollDrag || (GetCapture() != this))
+ // CScrollZoomView::OnRButtonUp(nFlags, point);
+ else
+ {
+ // if (opInProgress == gmoNone)
+ // ReleaseCapture();
+ // else
+ // ::SetCursor(::LoadCursor(NULL, IDC_ARROW));
+
+// scrollDrag = false;
+ }
+//}
+ }
+
+ update();
+}
+
+
+#if 0
+int MapView::OnMouseActivate(CWnd * wnd, unsigned int hitTest, unsigned int message)
+{
+ const int result = CScrollZoomView::OnMouseActivate(wnd, hitTest, message);
+
+ if ((result == MA_ACTIVATE) && GUEmapEatClicks)
+ return MA_ACTIVATEANDEAT;
+ else
+ return result;
+}
+
+
+bool MapView::OnMouseWheel(unsigned int nFlags, short zDelta, QPoint pt)
+{
+ if (nFlags == MK_CONTROL)
+ {
+ OnViewZoom((zDelta > 0) ? ID_VIEW_ZOOM_IN : ID_VIEW_ZOOM_OUT);
+ return TRUE;
+ }
+
+ return CScrollZoomView::OnMouseWheel(nFlags, zDelta, pt);
+}
+
+
+void MapView::OnSize(unsigned int nType, int cx, int cy)
+{
+ CScrollZoomView::OnSize(nType, cx, cy);
+
+ if (initialized()) // Make sure view has been initialized
+ setScrollBars();
+}
+
+
+void MapView::OnTimer(unsigned int idEvent)
+{
+ if (idEvent == menuTimer)
+ {
+ // We've held the button down long enough, switch to dragging:
+ SetCapture();
+ KillTimer(scrollDragTimer);
+ scrollDragTimer = 0;
+ scrollDrag = true;
+ ::SetCursor(handCursor);
+ }
+ else
+ CScrollZoomView::OnTimer(idEvent);
+}
+
+
+//
+// Update the view after the document changes:
+//
+// Input:
+// lHint:
+// dupDeletedRoom:
+// A room has just been deleted
+// dupPageCount:
+// The number of pages has changed
+// dupRoomComment:
+// A room comment was just changed
+// Do not invalidate the view unless pHint is not NULL.
+// dupNavigationMode:
+// We are entering navigation mode
+// Ignore pHint, do not invalidate the view, just make sure
+// exactly one room is selected and that it's visible.
+// pHint:
+// NULL means invalidate the entire view (but see lHint)
+// Otherwise, it's a QRect* to the area to invalidate
+//
+void MapView::OnUpdate(CView * pSender, LPARAM lHint, CObject * pHint)
+{
+ if (lHint == dupDeletedRoom && opInProgress != gmoDeleting && numSelected)
+ {
+ // Clear selection unless this is the view doing the deleting:
+ clearSelection();
+ selectDone();
+ }
+ else if (lHint == dupPageCount && opInProgress != gmoDeleting)
+ {
+ selectedPage.resize(GetDocument()->getPages().size(), 0);
+
+ if (numSelectedPages)
+ {
+ deselectPages();
+ selectDone();
+ }
+ }
+ else if (lHint == dupRoomComment)
+ {
+ // Update comment for this view, but don't override any other view:
+ static_cast<CMapApp*>(AfxGetApp())->setComment(this,
+ (selectedOne >= 0 ? &(GetDocument()->getRoom(selectedOne)) : NULL), false);
+
+ if (!pHint)
+ return; // Don't invalidate entire view
+ }
+
+ if (lHint == dupNavigationMode)
+ {
+ const MapDoc * doc = GetDocument();
+ ASSERT_VALID(doc);
+ const int numRooms = doc->room.size();
+
+ if (selectedOne < 0 || doc->room[selectedOne].isCorner())
+ selectOnlyRoom(0);
+
+ makeRoomVisible(selectedOne);
+ } // end if switching to navigation mode
+ else if (pHint)
+ {
+ QRect rect(*reinterpret_cast<const QRect *>(pHint));
+ CClientDC dc(this);
+ OnPrepareDC(&dc);
+ dc.LPtoDP(&rect);
+ rect.NormalizeRect();
+ InvalidateRect(rect);
+ }
+ else if (lHint != dupRoomComment)
+ Invalidate();
+}
+
+
+void MapView::OnUpdateEditAddCorner(CCmdUI* pCmdUI)
+{
+ pCmdUI->Enable(opInProgress == gmoAddCorner);
+}
+
+
+void MapView::OnUpdateEditPaste(CCmdUI* pCmdUI)
+{
+ pCmdUI->Enable((static_cast<CMapApp*>(AfxGetApp())->getClipboard() != NULL)
+ && !GetDocument()->locked);
+}
+
+
+//
+// Commands which require selected rooms and unlocked document:
+//
+// Edit|Clear
+// Edit|Cut
+// Edit|Copy
+// Edit|Select connected
+//
+void MapView::OnUpdateSelectedUnlocked(CCmdUI * pCmdUI)
+{
+ MapDoc * const doc = GetDocument();
+ ASSERT_VALID(doc);
+
+ bool selected = numSelected;
+
+ if ((pCmdUI->m_nID != ID_EDIT_SELECT_CONNECTED) && numSelectedPages)
+ {
+ if ((pCmdUI->m_nID != ID_EDIT_COPY)
+ && (doc->page.size() == numSelectedPages))
+ selected = false; // Can't delete all pages
+ else
+ selected = true;
+ }
+
+ pCmdUI->Enable(selected && !doc->locked);
+}
+
+
+//
+// Commands which require the document to be unlocked:
+//
+// Edit|Select all
+//
+void MapView::OnUpdateUnlocked(CCmdUI* pCmdUI)
+{
+ pCmdUI->Enable(!GetDocument()->locked);
+}
+
+
+//
+// Toggle the grid on and off:
+//
+void MapView::OnViewGrid()
+{
+ showGrid = !showGrid;
+ InvalidateRect(NULL);
+}
+
+
+void MapView::OnUpdateViewGrid(CCmdUI * pCmdUI)
+{
+ pCmdUI->SetCheck(showGrid);
+}
+
+
+void MapView::OnViewZoom(unsigned int cmd)
+{
+ ASSERT((cmd == ID_VIEW_ZOOM_IN) || (cmd == ID_VIEW_ZOOM_OUT));
+
+ if (cmd == ID_VIEW_ZOOM_OUT)
+ zoomTo(zoom % 10 ? zoom - zoom % 10 : zoom - 10);
+ else
+ zoomTo(zoom + 10 - zoom % 10);
+}
+
+
+void MapView::OnUpdateViewZoom(CCmdUI * pCmdUI)
+{
+ pCmdUI->Enable((pCmdUI->m_nID == ID_VIEW_ZOOM_IN)
+ ? (zoom < maxZoom) : (zoom > minZoom));
+}
+
+
+//
+// Redraw the window:
+//
+void MapView::OnWindowRefresh()
+{
+ InvalidateRect(NULL);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+// CRepaginateDlg dialog
+
+CRepaginateDlg::CRepaginateDlg(): CDialog(CRepaginateDlg::IDD, NULL)
+{
+ //{{AFX_DATA_INIT(CRepaginateDlg)
+ //}}AFX_DATA_INIT
+}
+
+BEGIN_MESSAGE_MAP(CRepaginateDlg, CDialog)
+ //{{AFX_MSG_MAP(CRepaginateDlg)
+ ON_BN_CLICKED(IDYES, OnYes)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP();
+
+/////////////////////////////////////////////////////////////////////////////
+// CRepaginateDlg message handlers
+
+
+bool CRepaginateDlg::OnInitDialog()
+{
+ CDialog::OnInitDialog();
+
+ SendDlgItemMessage(IDC_EXCLAMATION, STM_SETICON, (WPARAM) gueApp()->LoadStandardIcon(IDI_EXCLAMATION));
+ MessageBeep(MB_ICONEXCLAMATION);
+
+ return true; // return TRUE unless you set the focus to a control
+}
+
+
+void CRepaginateDlg::OnYes()
+{
+ EndDialog(IDYES);
+}
+#endif
+