Drawing the diagram
From TaskDepender
(Created page with "''This page describes how the GUI can draw the diagram.'' == Introduction == == Design == ----") |
|||
Line 1: | Line 1: | ||
''This page describes how the [[GUI]] can draw the diagram.'' | ''This page describes how the [[GUI]] can draw the diagram.'' | ||
− | == | + | == Description == |
== Design == | == Design == | ||
+ | |||
+ | |||
+ | == Implementation == | ||
+ | |||
+ | === Draw diagram === | ||
+ | |||
+ | <syntaxhighlight lang="cpp"> | ||
+ | void TMainForm::DrawDiagram(void) | ||
+ | { | ||
+ | // Clear | ||
+ | DiagramImage->Canvas->Brush->Color = clWhite; | ||
+ | DiagramImage->Canvas->FillRect(TRect(0, 0, DiagramImage->Width, DiagramImage->Height)); | ||
+ | |||
+ | DrawDeliverables(); | ||
+ | DrawTasks(); | ||
+ | DrawLines(); | ||
+ | |||
+ | if( DiagramCursorState == "Selecting" ) | ||
+ | { | ||
+ | DiagramImage->Canvas->Brush->Style = bsClear; | ||
+ | DiagramImage->Canvas->Pen->Color = clBlack; | ||
+ | DiagramImage->Canvas->Pen->Width = 1; | ||
+ | DiagramImage->Canvas->Pen->Style = psDash; | ||
+ | DiagramImage->Canvas->Rectangle(BeginXpos,BeginYpos,EndXpos,EndYpos); | ||
+ | } | ||
+ | |||
+ | DiagramImage->Repaint(); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | === Draw tasks === | ||
+ | |||
+ | <syntaxhighlight lang="cpp"> | ||
+ | void TMainForm::DrawTasks(void) | ||
+ | { | ||
+ | TaskC *task; | ||
+ | TStringList *taskName; | ||
+ | uint h; | ||
+ | uint w; | ||
+ | |||
+ | task = Admin->TasksAdmin->First(); | ||
+ | |||
+ | // All tasks belonging to the current container. | ||
+ | |||
+ | for( uint k=0; k<Admin->TasksAdmin->NumElements; k++) | ||
+ | { | ||
+ | if( task->Container != Admin->CurrentContainerId ) | ||
+ | { | ||
+ | // Task does not belong to this level. | ||
+ | task = task->next(); | ||
+ | continue; | ||
+ | } | ||
+ | |||
+ | taskName = new TStringList(); | ||
+ | taskName->Delimiter = DELIMITER_CHAR; | ||
+ | taskName->QuoteChar = QUOTE_CHAR; | ||
+ | taskName->DelimitedText = AnsiString( task->Name ); | ||
+ | |||
+ | // -- Determine required rectangle to wrap around the text -- | ||
+ | task->Height = 0; | ||
+ | task->Width = 0; | ||
+ | for(int line=0; line<taskName->Count; line++ ) | ||
+ | { | ||
+ | task->Height += DiagramImage->Canvas->TextHeight(taskName->Strings[line]); | ||
+ | |||
+ | w = DiagramImage->Canvas->TextWidth(taskName->Strings[line]); | ||
+ | if( task->Width < w ) | ||
+ | { | ||
+ | // Maximum width. | ||
+ | task->Width = w; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Set colors. | ||
+ | DiagramImage->Canvas->Pen->Style = psSolid; | ||
+ | DiagramImage->Canvas->Pen->Color = clBlack; | ||
+ | DiagramImage->Canvas->Pen->Width = 1; | ||
+ | |||
+ | if( task->NumContainedElements > 0 ) | ||
+ | { | ||
+ | DiagramImage->Canvas->Brush->Color = clBlue; | ||
+ | DiagramImage->Canvas->Font->Color = clWhite; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | DiagramImage->Canvas->Brush->Color = clAqua; | ||
+ | DiagramImage->Canvas->Font->Color = clBlack; | ||
+ | } | ||
+ | DiagramImage->Canvas->Rectangle( | ||
+ | task->Position.X-task->Width/2-Edge, | ||
+ | task->Position.Y-task->Height/2-Edge, | ||
+ | task->Position.X+task->Width/2+Edge, | ||
+ | task->Position.Y+task->Height/2+Edge ); | ||
+ | |||
+ | // Output the name lines. | ||
+ | h = 0; | ||
+ | for( int line=0;line < taskName->Count; line++ ) | ||
+ | { | ||
+ | w = DiagramImage->Canvas->TextWidth(taskName->Strings[line]); | ||
+ | DiagramImage->Canvas->TextOut( | ||
+ | task->Position.X-w/2, | ||
+ | task->Position.Y-task->Height/2+h, | ||
+ | taskName->Strings[line] ); | ||
+ | h += DiagramImage->Canvas->TextHeight(taskName->Strings[line]); | ||
+ | } | ||
+ | |||
+ | // Output the resource | ||
+ | |||
+ | if( task->ResourceId != NULL ) | ||
+ | { | ||
+ | int s = DiagramImage->Canvas->Font->Size; | ||
+ | DiagramImage->Canvas->Font->Size = 6; | ||
+ | |||
+ | DiagramImage->Canvas->Font->Color = clBlack; | ||
+ | DiagramImage->Canvas->Brush->Color = clWhite; | ||
+ | w = DiagramImage->Canvas->TextWidth(AnsiString(task->ResourceId)); | ||
+ | h = DiagramImage->Canvas->TextHeight(AnsiString(task->ResourceId)); | ||
+ | DiagramImage->Canvas->TextOut( | ||
+ | task->Position.X-w/2, | ||
+ | task->Position.Y-task->Height/2-1.3*h, | ||
+ | AnsiString(task->ResourceId) ); | ||
+ | |||
+ | DiagramImage->Canvas->Font->Size = s; | ||
+ | } | ||
+ | |||
+ | if( Admin->SelectedTasksIds->Find(task->Id) ) | ||
+ | { | ||
+ | // Draw selection lines around selected task. | ||
+ | DiagramImage->Canvas->Brush->Color = clRed; | ||
+ | DiagramImage->Canvas->PenPos.x = task->Position.X-task->Width/2; | ||
+ | DiagramImage->Canvas->PenPos.y = task->Position.Y-task->Height/2; | ||
+ | |||
+ | // Topleft | ||
+ | DiagramImage->Canvas->Ellipse( task->Position.X-task->Width/2-3-Edge, | ||
+ | task->Position.Y-task->Height/2-3-Edge, | ||
+ | task->Position.X-task->Width/2+3-Edge, | ||
+ | task->Position.Y-task->Height/2+3-Edge ); | ||
+ | // TopRight | ||
+ | DiagramImage->Canvas->Ellipse( task->Position.X+task->Width/2-3+Edge, | ||
+ | task->Position.Y-task->Height/2-3-Edge, | ||
+ | task->Position.X+task->Width/2+3+Edge, | ||
+ | task->Position.Y-task->Height/2+3-Edge ); | ||
+ | |||
+ | // Bottom right | ||
+ | DiagramImage->Canvas->Ellipse( task->Position.X+task->Width/2-3+Edge, | ||
+ | task->Position.Y+task->Height/2-3+Edge, | ||
+ | task->Position.X+task->Width/2+3+Edge, | ||
+ | task->Position.Y+task->Height/2+3+Edge ); | ||
+ | |||
+ | // Bottom left | ||
+ | DiagramImage->Canvas->Ellipse( task->Position.X-task->Width/2-3-Edge, | ||
+ | task->Position.Y+task->Height/2-3+Edge, | ||
+ | task->Position.X-task->Width/2+3-Edge, | ||
+ | task->Position.Y+task->Height/2+3+Edge ); | ||
+ | |||
+ | } | ||
+ | |||
+ | |||
+ | task = task->next(); | ||
+ | |||
+ | delete taskName; | ||
+ | } | ||
+ | |||
+ | // Print name of container task. | ||
+ | |||
+ | TaskC *containerTask = Admin->TasksAdmin->FindTask(Admin->CurrentContainerId); | ||
+ | if( containerTask != NULL ) | ||
+ | { | ||
+ | // Inside a container. | ||
+ | |||
+ | // Set color | ||
+ | DiagramImage->Canvas->Brush->Color = clWhite; | ||
+ | |||
+ | taskName = new TStringList(); | ||
+ | taskName->Delimiter = DELIMITER_CHAR; | ||
+ | taskName->QuoteChar = QUOTE_CHAR; | ||
+ | taskName->DelimitedText = AnsiString( containerTask->Name ); | ||
+ | |||
+ | AnsiString nameString = ""; | ||
+ | for( int i=0; i<taskName->Count; i++ ) | ||
+ | { | ||
+ | nameString = nameString + " " + taskName->Strings[i]; | ||
+ | } | ||
+ | |||
+ | h = DiagramImage->Canvas->TextHeight( nameString ); | ||
+ | w = DiagramImage->Canvas->TextWidth( nameString ); | ||
+ | |||
+ | DiagramImage->Canvas->TextOut( (DiagramImage->Width-w)/2, Edge, nameString ); | ||
+ | |||
+ | delete taskName; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | === Draw the deliverables === | ||
+ | |||
+ | <syntaxhighlight lang="cpp"> | ||
+ | void TMainForm::DrawDeliverables(void) | ||
+ | { | ||
+ | |||
+ | TStringList *deliverableName; | ||
+ | uint h; | ||
+ | uint w; | ||
+ | |||
+ | DeliverableC *deliverable = Admin->DeliverablesAdmin->First(); | ||
+ | |||
+ | // All deliverables in this container. | ||
+ | |||
+ | while( deliverable != NULL ) | ||
+ | { | ||
+ | if( deliverable->Container != Admin->CurrentContainerId) | ||
+ | { | ||
+ | // Deliverable does not belong to this level. | ||
+ | deliverable = deliverable->next(); | ||
+ | continue; | ||
+ | } | ||
+ | |||
+ | deliverableName = new TStringList(); | ||
+ | deliverableName->Delimiter = DELIMITER_CHAR; | ||
+ | deliverableName->QuoteChar = QUOTE_CHAR; | ||
+ | deliverableName->DelimitedText = AnsiString( deliverable->Name ); | ||
+ | |||
+ | // -- Determine required size of the rectangle to wrap around the text -- | ||
+ | |||
+ | deliverable->Height = 0; | ||
+ | deliverable->Width = 0; | ||
+ | for(int line=0; line<deliverableName->Count; line++ ) | ||
+ | { | ||
+ | deliverable->Height += DiagramImage->Canvas->TextHeight(deliverableName->Strings[line]); | ||
+ | |||
+ | w = DiagramImage->Canvas->TextWidth(deliverableName->Strings[line]); | ||
+ | if( deliverable->Width < w ) | ||
+ | { | ||
+ | // Maximum width. | ||
+ | deliverable->Width = w; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // -- Set colors -- | ||
+ | |||
+ | DiagramImage->Canvas->Pen->Style = psSolid; | ||
+ | DiagramImage->Canvas->Pen->Color = clBlack; | ||
+ | DiagramImage->Canvas->Pen->Width = 1; | ||
+ | |||
+ | if( deliverable->Available ) | ||
+ | { | ||
+ | if( deliverable->CloneId == 0 ) | ||
+ | { | ||
+ | DiagramImage->Canvas->Brush->Color = clGreen; | ||
+ | DiagramImage->Canvas->Font->Color = clWhite; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | DiagramImage->Canvas->Pen->Color = clGreen; | ||
+ | DiagramImage->Canvas->Brush->Color = clWhite; | ||
+ | DiagramImage->Canvas->Font->Color = clBlack; | ||
+ | } | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | // Deliverable not available yet. | ||
+ | |||
+ | if( deliverable->CloneId == 0 ) | ||
+ | { | ||
+ | DiagramImage->Canvas->Brush->Color = clRed; | ||
+ | DiagramImage->Canvas->Font->Color = clWhite; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | DiagramImage->Canvas->Pen->Color = clRed; | ||
+ | DiagramImage->Canvas->Brush->Color = clWhite; | ||
+ | DiagramImage->Canvas->Font->Color = clBlack; | ||
+ | } | ||
+ | |||
+ | // Make edge green if link available. | ||
+ | if( AnsiString(deliverable->Link) != "" ) | ||
+ | { | ||
+ | DiagramImage->Canvas->Font->Color = clGreen; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // -- Draw the rounded rectangle for the deliverable -- | ||
+ | |||
+ | DiagramImage->Canvas->RoundRect( | ||
+ | deliverable->Position.X-deliverable->Width/2-Edge, | ||
+ | deliverable->Position.Y-deliverable->Height/2-Edge, | ||
+ | deliverable->Position.X+deliverable->Width/2+Edge, | ||
+ | deliverable->Position.Y+deliverable->Height/2+Edge, | ||
+ | 4*Edge, 4*Edge ); | ||
+ | |||
+ | // -- Deliverable or dependency indicator for clone -- | ||
+ | |||
+ | if( ( deliverable->CloneId != 0 ) && ( deliverable->CloneId != MaxInt) ) | ||
+ | { | ||
+ | TaskC *container = Admin->TasksAdmin->FindTask(deliverable->Container); | ||
+ | DiagramImage->Canvas->Pen->Width = 1; | ||
+ | if( container->Dependencies->Find(deliverable->CloneId) ) | ||
+ | { | ||
+ | // Parent of clone is a dependency of the container task. | ||
+ | |||
+ | DiagramImage->Canvas->Pen->Color = clRed; | ||
+ | |||
+ | DiagramImage->Canvas->MoveTo( deliverable->Position.X-7, deliverable->Position.Y+deliverable->Height/2+8 ); | ||
+ | DiagramImage->Canvas->LineTo(deliverable->Position.X+4, deliverable->Position.Y+deliverable->Height/2+8 ); | ||
+ | |||
+ | DiagramImage->Canvas->LineTo(deliverable->Position.X, deliverable->Position.Y+deliverable->Height/2+6 ); | ||
+ | |||
+ | DiagramImage->Canvas->MoveTo( deliverable->Position.X+4, deliverable->Position.Y+deliverable->Height/2+8 ); | ||
+ | DiagramImage->Canvas->LineTo(deliverable->Position.X, deliverable->Position.Y+deliverable->Height/2+11 ); | ||
+ | |||
+ | DiagramImage->Canvas->Rectangle( deliverable->Position.X+5, deliverable->Position.Y+deliverable->Height/2+8-2, | ||
+ | deliverable->Position.X+10, deliverable->Position.Y+deliverable->Height/2+8+3 ); | ||
+ | |||
+ | } | ||
+ | else | ||
+ | { | ||
+ | |||
+ | // Parent of clone is a deliverable of the container task. | ||
+ | |||
+ | DiagramImage->Canvas->Pen->Color = clGreen; | ||
+ | |||
+ | DiagramImage->Canvas->Rectangle( deliverable->Position.X-7, deliverable->Position.Y+deliverable->Height/2+8-2, | ||
+ | deliverable->Position.X-2, deliverable->Position.Y+deliverable->Height/2+8+3 ); | ||
+ | |||
+ | DiagramImage->Canvas->MoveTo( deliverable->Position.X-2, deliverable->Position.Y+deliverable->Height/2+8 ); | ||
+ | DiagramImage->Canvas->LineTo( deliverable->Position.X+10, deliverable->Position.Y+deliverable->Height/2+8 ); | ||
+ | |||
+ | DiagramImage->Canvas->LineTo(deliverable->Position.X+6, deliverable->Position.Y+deliverable->Height/2+6 ); | ||
+ | |||
+ | DiagramImage->Canvas->MoveTo( deliverable->Position.X+10, deliverable->Position.Y+deliverable->Height/2+8 ); | ||
+ | DiagramImage->Canvas->LineTo(deliverable->Position.X+6, deliverable->Position.Y+deliverable->Height/2+11 ); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // -- Name lines -- | ||
+ | |||
+ | h = 0; // Keep track of the required height. | ||
+ | for( int line=0;line < deliverableName->Count; line++ ) | ||
+ | { | ||
+ | w = DiagramImage->Canvas->TextWidth(deliverableName->Strings[line]); | ||
+ | DiagramImage->Canvas->TextOut( | ||
+ | deliverable->Position.X-w/2, | ||
+ | deliverable->Position.Y-deliverable->Height/2+h, | ||
+ | deliverableName->Strings[line] ); | ||
+ | h += DiagramImage->Canvas->TextHeight(deliverableName->Strings[line]); | ||
+ | } | ||
+ | |||
+ | if( deliverable->ResourceId != NULL ) | ||
+ | { | ||
+ | int s = DiagramImage->Canvas->Font->Size; | ||
+ | DiagramImage->Canvas->Font->Size = 6; | ||
+ | |||
+ | DiagramImage->Canvas->Font->Color = clBlack; | ||
+ | DiagramImage->Canvas->Brush->Color = clWhite; | ||
+ | w = DiagramImage->Canvas->TextWidth(AnsiString(deliverable->ResourceId)); | ||
+ | h = DiagramImage->Canvas->TextHeight(AnsiString(deliverable->ResourceId)); | ||
+ | DiagramImage->Canvas->TextOut( | ||
+ | deliverable->Position.X-w/2, | ||
+ | deliverable->Position.Y-deliverable->Height/2-1.3*h, | ||
+ | AnsiString(deliverable->ResourceId) ); | ||
+ | |||
+ | DiagramImage->Canvas->Font->Size = s; | ||
+ | } | ||
+ | |||
+ | // -- Selection box -- | ||
+ | |||
+ | if( Admin->SelectedDeliverablesIds->Find(deliverable->Id) ) | ||
+ | { | ||
+ | // Deliverable is selected, draw selection lines around selected deliverable. | ||
+ | DiagramImage->Canvas->Brush->Color = clRed; | ||
+ | DiagramImage->Canvas->Pen->Color = clBlack; | ||
+ | DiagramImage->Canvas->Pen->Width = 1; | ||
+ | |||
+ | DiagramImage->Canvas->PenPos.x = deliverable->Position.X-deliverable->Width/2; | ||
+ | DiagramImage->Canvas->PenPos.y = deliverable->Position.Y-deliverable->Height/2; | ||
+ | |||
+ | // Topleft | ||
+ | DiagramImage->Canvas->Ellipse( deliverable->Position.X-deliverable->Width/2-3-Edge, | ||
+ | deliverable->Position.Y-deliverable->Height/2-3-Edge, | ||
+ | deliverable->Position.X-deliverable->Width/2+3-Edge, | ||
+ | deliverable->Position.Y-deliverable->Height/2+3-Edge ); | ||
+ | // TopRight | ||
+ | DiagramImage->Canvas->Ellipse( deliverable->Position.X+deliverable->Width/2-3+Edge, | ||
+ | deliverable->Position.Y-deliverable->Height/2-3-Edge, | ||
+ | deliverable->Position.X+deliverable->Width/2+3+Edge, | ||
+ | deliverable->Position.Y-deliverable->Height/2+3-Edge ); | ||
+ | |||
+ | // Bottom right | ||
+ | DiagramImage->Canvas->Ellipse( deliverable->Position.X+deliverable->Width/2-3+Edge, | ||
+ | deliverable->Position.Y+deliverable->Height/2-3+Edge, | ||
+ | deliverable->Position.X+deliverable->Width/2+3+Edge, | ||
+ | deliverable->Position.Y+deliverable->Height/2+3+Edge ); | ||
+ | |||
+ | // Bottom left | ||
+ | DiagramImage->Canvas->Ellipse( deliverable->Position.X-deliverable->Width/2-3-Edge, | ||
+ | deliverable->Position.Y+deliverable->Height/2-3+Edge, | ||
+ | deliverable->Position.X-deliverable->Width/2+3-Edge, | ||
+ | deliverable->Position.Y+deliverable->Height/2+3+Edge ); | ||
+ | |||
+ | } | ||
+ | |||
+ | deliverable = deliverable->next(); | ||
+ | |||
+ | delete deliverableName; | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | === Draw lines === | ||
+ | |||
+ | <syntaxhighlight lang="cpp"> | ||
+ | void TMainForm::DrawLines(void) | ||
+ | { | ||
+ | // Loop through all the tasks and draw the in and output lines. | ||
+ | |||
+ | TaskC *task; | ||
+ | DeliverableC *deliverable; | ||
+ | |||
+ | DiagramImage->Canvas->Pen->Style = psSolid; | ||
+ | |||
+ | task = Admin->TasksAdmin->First(); | ||
+ | while( task != NULL ) | ||
+ | { | ||
+ | if( task->Container != Admin->CurrentContainerId ) | ||
+ | { | ||
+ | // Not in the level. | ||
+ | task = task->next(); | ||
+ | continue; | ||
+ | } | ||
+ | // Loop through all inputs. | ||
+ | DiagramImage->Canvas->Pen->Color = clRed; | ||
+ | DiagramImage->Canvas->Pen->Width = 1; | ||
+ | for( uint k=0; k < task->Dependencies->NumElements; k++ ) | ||
+ | { | ||
+ | deliverable = Admin->DeliverablesAdmin->FindDeliverable( task->Dependencies->Element[k] ); | ||
+ | if( deliverable != NULL ) | ||
+ | { | ||
+ | // Draw arrow | ||
+ | DrawArrowLine( task, deliverable, true ); | ||
+ | |||
+ | } | ||
+ | } | ||
+ | |||
+ | // Loop through all outputs. | ||
+ | DiagramImage->Canvas->Pen->Color = clGreen; | ||
+ | DiagramImage->Canvas->Pen->Width = 1; | ||
+ | for( uint k=0; k < task->Deliverables->NumElements; k++ ) | ||
+ | { | ||
+ | deliverable = Admin->DeliverablesAdmin->FindDeliverable( task->Deliverables->Element[k] ); | ||
+ | if( deliverable != NULL ) | ||
+ | { | ||
+ | // Draw arrow | ||
+ | DrawArrowLine( task, deliverable, false ); | ||
+ | } | ||
+ | } | ||
+ | task = task->next(); | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | <syntaxhighlight lang="cpp"> | ||
+ | //--------------------------------------------------------------------------- | ||
+ | // DrawArrow | ||
+ | // Draws an arrow onto the line between the task and the deliverable. | ||
+ | //--------------------------------------------------------------------------- | ||
+ | void TMainForm::DrawArrowLine(TaskC *task, DeliverableC *deliverable, bool dependency ) | ||
+ | { | ||
+ | double x1,y1,x2,y2,x_left,x_right,y_top,y_bottom,a,c, | ||
+ | x_task,y_task, | ||
+ | x_deliverable,y_deliverable, | ||
+ | x_m,y_m; | ||
+ | bool vertical = false; | ||
+ | bool horizontal; | ||
+ | uint marginDeliverable, marginTask; | ||
+ | |||
+ | if( dependency ) | ||
+ | { | ||
+ | marginTask = 1; | ||
+ | marginDeliverable = 0; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | marginTask = 0; | ||
+ | marginDeliverable = 1; | ||
+ | } | ||
+ | |||
+ | // -- Determine the equation for the line -- | ||
+ | |||
+ | x1 = (double)task->Position.X; | ||
+ | y1 = (double)task->Position.Y; | ||
+ | |||
+ | x2 = (double)deliverable->Position.X; | ||
+ | y2 = (double)deliverable->Position.Y; | ||
+ | |||
+ | vertical = ( fabs(x1-x2) < 0.001 ); | ||
+ | |||
+ | if( !vertical) | ||
+ | { | ||
+ | horizontal = (fabs(y1-y2) < 0.001 ); | ||
+ | |||
+ | a = (y1-y2)/(x1-x2); | ||
+ | c = y1-a*x1; | ||
+ | } | ||
+ | |||
+ | // -- Determine midpoint of the line by determining the crossing edge -- | ||
+ | |||
+ | // Determine crossing edge point for task. | ||
+ | if( !vertical ) | ||
+ | { | ||
+ | x_left = x1-(double)task->Width/2-Edge-marginTask; | ||
+ | x_right = x1+(double)task->Width/2+Edge+marginTask; | ||
+ | y_top = y1-(double)task->Height/2-Edge-marginTask; | ||
+ | y_bottom = y1+(double)task->Height/2+Edge+marginTask; | ||
+ | |||
+ | if( !horizontal && | ||
+ | y1>y2 && | ||
+ | x_left<=(y_top-c)/a && | ||
+ | (y_top-c)/a<=x_right ) | ||
+ | { | ||
+ | // upper edge | ||
+ | x_task = (y_top-c)/a; | ||
+ | y_task = y_top; | ||
+ | } | ||
+ | |||
+ | else if( x1<x2 && | ||
+ | y_top<=(a*x_right+c) && | ||
+ | (a*x_right+c)<=y_bottom ) | ||
+ | { | ||
+ | // Right edge | ||
+ | x_task = x_right; | ||
+ | y_task = a*x_right+c; | ||
+ | } | ||
+ | else if( !horizontal && | ||
+ | y1<y2 && | ||
+ | x_left<=(y_bottom-c)/a && | ||
+ | (y_bottom-c)/a<=x_right ) | ||
+ | { | ||
+ | // Bottom edge | ||
+ | x_task = (y_bottom-c)/a; | ||
+ | y_task = y_bottom; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | // Left edge | ||
+ | x_task = x_left; | ||
+ | y_task = a*x_left+c; | ||
+ | } | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | // -- Vertical -- | ||
+ | if( y1>y2 ) | ||
+ | { | ||
+ | // upper edge | ||
+ | x_task = x1; | ||
+ | y_task = y1-(double)task->Height/2-Edge-marginTask; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | // Bottom edge | ||
+ | x_task = x1; | ||
+ | y_task = y1+(double)task->Height/2+Edge+marginTask; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Determine crossing edge point for deliverable. | ||
+ | if( !vertical ) | ||
+ | { | ||
+ | x_left = x2-(double)deliverable->Width/2-Edge-marginDeliverable; | ||
+ | x_right = x2+(double)deliverable->Width/2+Edge+marginDeliverable; | ||
+ | y_top = y2-(double)deliverable->Height/2-Edge-marginDeliverable; | ||
+ | y_bottom = y2+(double)deliverable->Height/2+Edge+marginDeliverable; | ||
+ | |||
+ | if( !horizontal && | ||
+ | y2>y1 && | ||
+ | x_left<=(y_top-c)/a && | ||
+ | (y_top-c)/a<=x_right ) | ||
+ | { | ||
+ | // upper edge | ||
+ | x_deliverable = (y_top-c)/a; | ||
+ | y_deliverable = y_top; | ||
+ | } | ||
+ | |||
+ | else if( x2<x1 && | ||
+ | y_top<=(a*x_right+c) && | ||
+ | (a*x_right+c)<=y_bottom ) | ||
+ | { | ||
+ | // Right edge | ||
+ | x_deliverable = x_right; | ||
+ | y_deliverable = a*x_right+c; | ||
+ | } | ||
+ | else if( !horizontal && | ||
+ | y2<y1 && | ||
+ | x_left<=(y_bottom-c)/a && | ||
+ | (y_bottom-c)/a<=x_right ) | ||
+ | { | ||
+ | // Bottom edge | ||
+ | x_deliverable = (y_bottom-c)/a; | ||
+ | y_deliverable = y_bottom; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | // Left edge | ||
+ | x_deliverable = x_left; | ||
+ | y_deliverable = a*x_left+c; | ||
+ | } | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | // -- Vertical -- | ||
+ | if( y2>y1 ) | ||
+ | { | ||
+ | // upper edge | ||
+ | x_deliverable = x2; | ||
+ | y_deliverable = y2-(double)deliverable->Height/2-Edge-marginDeliverable; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | // Bottom edge | ||
+ | x_deliverable = x2; | ||
+ | y_deliverable = y2+(double)deliverable->Height/2+Edge+marginDeliverable; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | DiagramImage->Canvas->Pen->Width = 1; | ||
+ | if( dependency ) | ||
+ | { | ||
+ | DiagramImage->Canvas->Pen->Color = clRed; | ||
+ | DrawArrow( x_deliverable, y_deliverable, x_task, y_task ); | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | DiagramImage->Canvas->Pen->Color = clGreen; | ||
+ | DrawArrow( x_task, y_task, x_deliverable, y_deliverable ); | ||
+ | } | ||
+ | |||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | <syntaxhighlight lang="cpp"> | ||
+ | void TMainForm::DrawArrow( double begin_x, double begin_y, double end_x, double end_y ) | ||
+ | { | ||
+ | Extended b; | ||
+ | Extended deltaX; | ||
+ | Extended deltaY; | ||
+ | |||
+ | double angle = 30; | ||
+ | double length = 10; | ||
+ | |||
+ | // Draw the line from begin to end. | ||
+ | DiagramImage->Canvas->MoveTo( begin_x, begin_y ); | ||
+ | DiagramImage->Canvas->LineTo( end_x, end_y ); | ||
+ | |||
+ | if( begin_x != end_x ) // checks for division by zero | ||
+ | { | ||
+ | b = ArcTan2( end_y-begin_y, begin_x-end_x ); | ||
+ | |||
+ | |||
+ | if (begin_x < end_x) | ||
+ | { | ||
+ | deltaX = length * cos(M_PI-b+DegToRad(angle)); | ||
+ | deltaY = length * sin(M_PI-b+DegToRad(angle)); | ||
+ | |||
+ | DiagramImage->Canvas->MoveTo(end_x, end_y); | ||
+ | DiagramImage->Canvas->LineTo((double)end_x - deltaX, (double)end_y - deltaY); | ||
+ | |||
+ | deltaX = length * cos(M_PI-b-DegToRad(angle)); | ||
+ | deltaY = length * sin(M_PI-b-DegToRad(angle)); | ||
+ | |||
+ | DiagramImage->Canvas->MoveTo(end_x, end_y); | ||
+ | DiagramImage->Canvas->LineTo((double)end_x - deltaX, (double)end_y - deltaY); | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | deltaX = length * cos(b+DegToRad(angle)); | ||
+ | deltaY = length * sin(b+DegToRad(angle)); | ||
+ | |||
+ | DiagramImage->Canvas->MoveTo(end_x, end_y); | ||
+ | DiagramImage->Canvas->LineTo((double)end_x + deltaX, (double)end_y - deltaY); | ||
+ | |||
+ | deltaX = length * cos(b-DegToRad(angle)); | ||
+ | deltaY = length * sin(b-DegToRad(angle)); | ||
+ | |||
+ | DiagramImage->Canvas->MoveTo(end_x, end_y); | ||
+ | DiagramImage->Canvas->LineTo((double)end_x + deltaX, (double)end_y - deltaY); | ||
+ | } | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | if( begin_y < end_y ) | ||
+ | { | ||
+ | deltaX = length * cos(DegToRad(90-angle)); | ||
+ | deltaY = length * sin(DegToRad(90-angle)); | ||
+ | |||
+ | DiagramImage->Canvas->MoveTo(end_x, end_y); | ||
+ | DiagramImage->Canvas->LineTo((double)end_x + deltaX, (double)end_y - deltaY); | ||
+ | |||
+ | deltaX = length * cos(DegToRad(90+angle)); | ||
+ | deltaY = length * sin(DegToRad(90+angle)); | ||
+ | |||
+ | DiagramImage->Canvas->MoveTo(end_x, end_y); | ||
+ | DiagramImage->Canvas->LineTo((double)end_x + deltaX, (double)end_y - deltaY); | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | deltaX = length * cos(DegToRad(90-angle)); | ||
+ | deltaY = length * sin(DegToRad(90-angle)); | ||
+ | |||
+ | DiagramImage->Canvas->MoveTo(end_x, end_y); | ||
+ | DiagramImage->Canvas->LineTo((double)end_x + deltaX, (double)end_y + deltaY); | ||
+ | |||
+ | deltaX = length * cos(DegToRad(90+angle)); | ||
+ | deltaY = length * sin(DegToRad(90+angle)); | ||
+ | |||
+ | DiagramImage->Canvas->MoveTo(end_x, end_y); | ||
+ | DiagramImage->Canvas->LineTo((double)end_x + deltaX, (double)end_y + deltaY); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
---- | ---- |