summaryrefslogtreecommitdiff
path: root/src/linux/Edge+Render.m
blob: 2e5f127f21ff402c795f5c9406ea736a6919b7af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/*
 * Copyright 2011  Alex Merry <dev@randomguy3.me.uk>
 * Copyright 2010  Chris Heunen
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#import "Edge+Render.h"
#import "Node+Render.h"
#import "../common/util.h"

static const float edgeWidth = 2.0;
static const float cpRadius = 3.0;
static const float cpLineWidth = 1.0;

@implementation Edge (Render)

+ (float) controlPointRadius {
    return cpRadius;
}

- (float) controlDistanceWithTransformer:(Transformer*)transformer {
    NSPoint c_source = [transformer toScreen:src];
    NSPoint c_target = [transformer toScreen:targ];
    const float dx = (c_target.x - c_source.x);
    const float dy = (c_target.y - c_source.y);
    if (dx == 0 && dy == 0) {
        return [transformer scaleToScreen:weight];
    } else {
        return NSDistanceBetweenPoints(c_source, c_target) * weight;
    }
}

- (void) renderControlsToSurface:(id <Surface>)surface withContext:(id<RenderContext>)context {
    Transformer *transformer = [surface transformer];

    [context saveState];

    [self updateControls];

    NSPoint c_source = [transformer toScreen:src];
    NSPoint c_target = [transformer toScreen:targ];
    NSPoint c_mid = [transformer toScreen:mid];

    const float dx = (c_target.x - c_source.x);
    const float dy = (c_target.y - c_source.y);

    [context setLineWidth:cpLineWidth];
    RColor fillColor = MakeRColor (1.0, 1.0, 1.0, 0.5);

    // draw a circle at the mid point
    [context startPath];
    [context circleAt:c_mid withRadius:cpRadius];
    [context strokePathWithColor:MakeSolidRColor(0, 0, 1) andFillWithColor:fillColor];

    //[context setAntialiasMode:AntialiasDisabled];

    // size of control circles
    float c_dist = 0.0f;
    if (dx == 0 && dy == 0) {
        c_dist = [transformer scaleToScreen:weight];
    } else {
        c_dist = NSDistanceBetweenPoints(c_source, c_target) * weight;
    }

    // basic bend is blue, in-out is green
    RColor controlTrackColor;
    if ([self bendMode] == EdgeBendModeBasic) {
        controlTrackColor = MakeRColor (0.0, 0.0, 1.0, 0.4);
    } else {
        controlTrackColor = MakeRColor (0.0, 0.7, 0.0, 0.4);
    }

    [context startPath];
    [context circleAt:c_source withRadius:c_dist];
    if (dx != 0 || dy != 0) {
        [context circleAt:c_target withRadius:c_dist];
    }
    [context strokePathWithColor:controlTrackColor];

    RColor handleColor = MakeRColor (1.0, 0.0, 1.0, 0.6);
    if ([self bendMode] == EdgeBendModeBasic) {
        if (bend % 45 != 0) {
            handleColor = MakeRColor (0.0, 0.0, 0.1, 0.4);
        }
    } else if ([self bendMode] == EdgeBendModeInOut) {
        if (outAngle % 45 != 0) {
            handleColor = MakeRColor (0.0, 0.7, 0.0, 0.4);
        }
    }

    NSPoint c_cp1 = [transformer toScreen:cp1];
    [context moveTo:c_source];
    [context lineTo:c_cp1];
    [context circleAt:c_cp1 withRadius:cpRadius];
    [context strokePathWithColor:handleColor];

    if ([self bendMode] == EdgeBendModeInOut) {
        // recalculate color based on inAngle
        if (inAngle % 45 == 0) {
            handleColor = MakeRColor (1.0, 0.0, 1.0, 0.6);
        } else {
            handleColor = MakeRColor (0.0, 0.7, 0.0, 0.4);
        }
    }

    NSPoint c_cp2 = [transformer toScreen:cp2];
    [context moveTo:c_target];
    [context lineTo:c_cp2];
    [context circleAt:c_cp2 withRadius:cpRadius];
    [context strokePathWithColor:handleColor];

    [context restoreState];
}

- (void) createStrokePathInContext:(id<RenderContext>)context withTransformer:(Transformer*)transformer {
    NSPoint c_source = [transformer toScreen:src];
    NSPoint c_cp1 = [transformer toScreen:cp1];
    NSPoint c_cp2 = [transformer toScreen:cp2];
    NSPoint c_target = [transformer toScreen:targ];

    [context startPath];
    [context moveTo:c_source];
    [context curveTo:c_target withCp1:c_cp1 andCp2:c_cp2];

	if ([self style] != nil) {
        // draw edge decoration
        switch ([[self style] decorationStyle]) {
            case ED_None:
                break;
            case ED_Tick:
				[context moveTo:[transformer toScreen:[self leftNormal]]];
				[context lineTo:[transformer toScreen:[self rightNormal]]];
                break;
            case ED_Arrow:
				[context moveTo:[transformer toScreen:[self leftNormal]]];
				[context lineTo:[transformer toScreen:[self midTan]]];
				[context lineTo:[transformer toScreen:[self rightNormal]]];
                break;
        }
    }

}

- (void) renderToSurface:(id <Surface>)surface withContext:(id<RenderContext>)context selected:(BOOL)selected {
    [self updateControls];

    [context saveState];
    [context setLineWidth:edgeWidth];
    [self createStrokePathInContext:context withTransformer:[surface transformer]];
    RColor color = BlackRColor;
    if (selected) {
        color.alpha = 0.5;
    }
    [context strokePathWithColor:color];
    [context restoreState];

    if (selected) {
        [self renderControlsToSurface:surface withContext:context];
    }

	if ([self hasEdgeNode]) {
		NSPoint labelPt = [[surface transformer] toScreen:[self mid]];
		[[self edgeNode] renderLabelAt:labelPt
			               withContext:context];
	}
}

- (NSRect) renderedBoundsWithTransformer:(Transformer*)t whenSelected:(BOOL)selected {
    NSRect bRect = [t rectToScreen:[self boundingRect]];
    if (selected) {
        float c_dist = [self controlDistanceWithTransformer:t];
        return NSInsetRect (bRect, -c_dist, -c_dist);
    } else {
        return bRect;
    }
}

- (BOOL) hitByPoint:(NSPoint)p onSurface:(id<Surface>)surface withFuzz:(float)fuzz {
    [self updateControls];

    NSRect boundingRect = [[surface transformer] rectToScreen:[self boundingRect]];
    if (!NSPointInRect(p, NSInsetRect(boundingRect, -fuzz, -fuzz))) {
        return NO;
    }

    id<RenderContext> cr = [surface createRenderContext];

    [cr setLineWidth:edgeWidth + 2 * fuzz];
    [self createStrokePathInContext:cr withTransformer:[surface transformer]];

    return [cr strokeIncludesPoint:p];
}

@end

// vim:ft=objc:ts=4:noet:sts=4:sw=4