using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
namespace SketchAssistantWPF
{
public class MVP_Presenter
{
///
/// The View of the MVP-Model, in this case Form1.
///
MVP_View programView;
///
/// The Model of the MVP-Model.
///
MVP_Model programModel;
///
/// A dictionary connecting the id of an InternalLine with the respective Polyline in the right canvas.
///
Dictionary rightPolyLines;
ImageDimension CanvasSizeLeft = new ImageDimension(0,0);
ImageDimension CanvasSizeRight = new ImageDimension(0, 0);
ImageDimension ImageSizeLeft = new ImageDimension(0, 0);
ImageDimension ImageSizeRight = new ImageDimension(0, 0);
/*******************/
/*** ENUMERATORS ***/
/*******************/
public enum MouseAction
{
Click,
Down,
Up,
Move
}
/***********************/
/*** CLASS VARIABLES ***/
/***********************/
///
/// Instance of FileImporter to handle drawing imports.
///
private FileImporter fileImporter;
public MVP_Presenter(MVP_View form)
{
programView = form;
programModel = new MVP_Model(this);
//Initialize Class Variables
fileImporter = new FileImporter();
}
/***********************************/
/*** FUNCTIONS VIEW -> PRESENTER ***/
/***********************************/
///
/// Pass-trough function to update the appropriate information of the model, when the window is resized.
///
/// The new size of the left picture box.
/// The new size of the left picture box.
public void Resize(Tuple leftPBS, Tuple rightPBS)
{
CanvasSizeLeft.ChangeDimension(leftPBS.Item1, leftPBS.Item2);
CanvasSizeRight.ChangeDimension(rightPBS.Item1, rightPBS.Item2);
programModel.UpdateSizes(CanvasSizeRight);
programModel.ResizeEvent(CanvasSizeLeft, CanvasSizeRight);
}
///
/// Display a new FileDialog to load a collection of lines.
///
public void ExamplePictureToolStripMenuItemClick()
{
var okToContinue = true;
if (programModel.HasUnsavedProgress())
{
okToContinue = programView.ShowWarning("You have unsaved progress. Continue?");
}
if (okToContinue)
{
var fileNameTup = programView.openNewDialog("Interactive Sketch-Assistant Drawing|*.isad");
if (!fileNameTup.Item1.Equals("") && !fileNameTup.Item2.Equals(""))
{
programView.SetToolStripLoadStatus(fileNameTup.Item2);
Tuple> values = fileImporter.ParseISADInputFile(fileNameTup.Item1);
programModel.SetLeftLineList(values.Item1, values.Item2, values.Item3);
programModel.ResetRightImage();
programModel.CanvasActivated();
programModel.ChangeState(true);
programView.EnableTimer();
ClearRightLines();
}
}
}
///
/// Pass-trough function to change the drawing state of the model.
///
/// Indicates if the program is in drawing (true) or deletion (false) mode.
public void ChangeState(bool NowDrawing)
{
programModel.ChangeState(NowDrawing);
}
///
/// Pass-trough function to undo an action.
///
public void Undo()
{
programModel.Undo();
}
///
/// Pass-trough function to redo an action.
///
public void Redo()
{
programModel.Redo();
}
///
/// Pass-trough function for ticking the model.
///
public void Tick()
{
programModel.Tick();
}
///
/// Checks if there is unsaved progress, and promts the model to generate a new canvas if not.
///
public void NewCanvas()
{
var okToContinue = true;
if (programModel.HasUnsavedProgress())
{
okToContinue = programView.ShowWarning("You have unsaved progress. Continue?");
}
if (okToContinue)
{
programModel.ResizeEvent(CanvasSizeLeft, CanvasSizeRight);
programModel.ResetRightImage();
programModel.CanvasActivated();
programModel.ChangeState(true);
programView.EnableTimer();
ClearRightLines();
}
}
///
/// Pass-trough when the mouse is moved.
///
/// The action which is sent by the View.
/// The Mouse event arguments.
public void MouseEvent(MouseAction mouseAction, Point position)
{
switch (mouseAction)
{
case MouseAction.Move:
programModel.SetCurrentCursorPosition(position);
break;
default:
break;
}
}
///
/// Pass-trough function that calls the correct Mouse event of the model, when the mouse is clicked.
///
/// The action which is sent by the View.
/// The Mouse event arguments.
public void MouseEvent(MouseAction mouseAction)
{
switch (mouseAction)
{
case MouseAction.Click:
programModel.MouseDown();
programModel.Tick();
programModel.MouseUp();
break;
case MouseAction.Down:
programModel.MouseDown();
break;
case MouseAction.Up:
programModel.MouseUp();
break;
default:
break;
}
}
/************************************/
/*** FUNCTIONS MODEL -> PRESENTER ***/
/************************************/
///
/// Updates the currentline
///
/// The points of the current line.
public void UpdateCurrentLine(List linepoints)
{
Polyline currentLine = new Polyline();
currentLine.Stroke = Brushes.Black;
currentLine.Points = new PointCollection(linepoints);
programView.DisplayCurrLine(currentLine);
}
///
/// Clears all Lines in the right canvas.
///
public void ClearRightLines()
{
programView.RemoveAllRightLines();
rightPolyLines = new Dictionary();
}
///
/// A function to update the displayed lines in the right canvas.
///
public void UpdateRightLines(List> lines)
{
foreach(Tuple tup in lines)
{
var status = tup.Item1;
var line = tup.Item2;
if (!rightPolyLines.ContainsKey(line.GetID()))
{
Polyline newLine = new Polyline();
newLine.Points = line.GetPointCollection();
rightPolyLines.Add(line.GetID(), newLine);
programView.AddNewLineRight(newLine);
}
SetVisibility(rightPolyLines[line.GetID()], status);
}
}
///
/// A function to update the displayed lines in the left canvas.
///
public void UpdateLeftLines(List lines)
{
programView.RemoveAllLeftLines();
foreach (InternalLine line in lines)
{
Polyline newLine = new Polyline();
newLine.Stroke = Brushes.Black;
newLine.Points = line.GetPointCollection();
programView.AddNewLineLeft(newLine);
}
programView.SetCanvasState("LeftCanvas", true);
programView.SetCanvasState("RightCanvas", true);
}
///
/// Called by the model when the state of the Program changes.
/// Changes the look of the UI according to the current state of the model.
///
/// If the model is in Drawing Mode
/// If actions in the model can be undone
/// If actions in the model can be redone
/// If the right canvas is active
/// If an image is loaded in the model
public void UpdateUIState(bool inDrawingMode, bool canUndo, bool canRedo, bool canvasActive, bool graphicLoaded)
{
Dictionary dict = new Dictionary {
{"canvasButton", MainWindow.ButtonState.Enabled }, {"drawButton", MainWindow.ButtonState.Disabled}, {"deleteButton",MainWindow.ButtonState.Disabled },
{"undoButton", MainWindow.ButtonState.Disabled },{"redoButton", MainWindow.ButtonState.Disabled}};
if (canvasActive)
{
if (inDrawingMode)
{
dict["drawButton"] = MainWindow.ButtonState.Active;
dict["deleteButton"] = MainWindow.ButtonState.Enabled;
}
else
{
dict["drawButton"] = MainWindow.ButtonState.Enabled;
dict["deleteButton"] = MainWindow.ButtonState.Active;
}
if (canUndo) { dict["undoButton"] = MainWindow.ButtonState.Enabled; }
if (canRedo) { dict["redoButton"] = MainWindow.ButtonState.Enabled; }
}
foreach (KeyValuePair entry in dict)
{
programView.SetToolStripButtonStatus(entry.Key, entry.Value);
}
programView.SetCanvasState("RightCanvas", canvasActive);
programView.SetCanvasState("LeftCanvas", graphicLoaded);
}
///
/// Pass-trough function to display an info message in the view.
///
/// The message.
public void PassMessageToView(String msg)
{
programView.ShowInfoMessage(msg);
}
///
/// Pass-trough function to update the display of the last action taken.
///
/// The new last action taken.
public void PassLastActionTaken(String msg)
{
programView.SetLastActionTakenText(msg);
}
/*************************/
/*** HELPING FUNCTIONS ***/
/*************************/
///
/// Sets the visibility of a polyline.
///
/// The polyline
/// Whether or not it should be visible.
private void SetVisibility(Polyline line, bool visible)
{
if (!visible)
{
line.Opacity = 0.00001;
}
else
{
line.Opacity = 1;
}
}
///
/// A function that calculates the coordinates of a point on a zoomed in image.
///
/// The position of the mouse cursor
/// The real coordinates of the mouse cursor on the image
private Point ConvertCoordinates(Point cursorPosition)
{
if (!programModel.canvasActive) { return cursorPosition; }
if (programModel.canvasActive && !programModel.graphicLoaded) { return cursorPosition; }
ImageDimension rightImageDimensions = programModel.rightImageSize;
Point realCoordinates = new Point(0, 0);
int widthImage = rightImageDimensions.Width;
int heightImage = rightImageDimensions.Height;
int widthBox = programModel.rightImageBoxWidth;
int heightBox = programModel.rightImageBoxHeight;
if (heightImage == 0 && widthImage == 0)
{
return cursorPosition;
}
float imageRatio = (float)widthImage / (float)heightImage;
float containerRatio = (float)widthBox / (float)heightBox;
if (imageRatio >= containerRatio)
{
//Image is wider than it is high
float zoomFactor = (float)widthImage / (float)widthBox;
float scaledHeight = heightImage / zoomFactor;
float filler = (heightBox - scaledHeight) / 2;
realCoordinates.X = (int)(cursorPosition.X * zoomFactor);
realCoordinates.Y = (int)((cursorPosition.Y - filler) * zoomFactor);
}
else
{
//Image is higher than it is wide
float zoomFactor = (float)heightImage / (float)heightBox;
float scaledWidth = widthImage / zoomFactor;
float filler = (widthBox - scaledWidth) / 2;
realCoordinates.X = (int)((cursorPosition.X - filler) * zoomFactor);
realCoordinates.Y = (int)(cursorPosition.Y * zoomFactor);
}
return realCoordinates;
}
}
}