1/* 2 PPCanvasView_ColorRampToolOverlay.m 3 4 Copyright 2013-2018 Josh Freeman 5 http://www.twilightedge.com 6 7 This file is part of PikoPixel for Mac OS X and GNUstep. 8 PikoPixel is a graphical application for drawing & editing pixel-art images. 9 10 PikoPixel is free software: you can redistribute it and/or modify it under 11 the terms of the GNU Affero General Public License as published by the 12 Free Software Foundation, either version 3 of the License, or (at your 13 option) any later version approved for PikoPixel by its copyright holder (or 14 an authorized proxy). 15 16 PikoPixel is distributed in the hope that it will be useful, but WITHOUT ANY 17 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more 19 details. 20 21 You should have received a copy of the GNU Affero General Public License 22 along with this program. If not, see <http://www.gnu.org/licenses/>. 23*/ 24 25#import "PPCanvasView.h" 26 27#import "NSBitmapImageRep_PPUtilities.h" 28#import "NSBezierPath_PPUtilities.h" 29#import "NSColor_PPUtilities.h" 30#import "PPGeometry.h" 31 32 33#define kMinZoomFactorToDrawOverlay 5 34 35#define kMinZoomFactorToDrawWideOutlines 14 36#define kMinZoomFactorToDrawXMarks 8 37 38 39#define kOverlayPathLineWidth_WideOutline (2.0) 40#define kOverlayPathLineWidth_NarrowOutline (0.0) 41 42#define kOverlayPathLineWidth_XMarkLine (0.0) 43#define kOverlayPathLineWidth_XMarkHalo (2.0) 44 45 46#define kUIColor_ColorRampToolOverlay_Outline \ 47 [NSColor ppDiagonalLinePatternColorWithLineWidth: 2.0f \ 48 color1: [NSColor blackColor] \ 49 color2: [NSColor whiteColor]] 50 51#define kUIColor_ColorRampToolOverlay_XMarkLine \ 52 [NSColor ppSRGBColorWithWhite: 0.6 alpha: 0.7] 53 54#define kUIColor_ColorRampToolOverlay_XMarkHalo \ 55 [NSColor ppSRGBColorWithWhite: 0.85 alpha: 0.7] 56 57 58static NSColor *gOverlayColor_Outline = nil, *gOverlayColor_XMarkLine = nil, 59 *gOverlayColor_XMarkHalo = nil; 60 61 62@implementation PPCanvasView (ColorRampToolOverlay) 63 64+ (void) initializeColorRampToolOverlay 65{ 66 gOverlayColor_Outline = [kUIColor_ColorRampToolOverlay_Outline retain]; 67 68 gOverlayColor_XMarkLine = [kUIColor_ColorRampToolOverlay_XMarkLine retain]; 69 70 gOverlayColor_XMarkHalo = [kUIColor_ColorRampToolOverlay_XMarkHalo retain]; 71} 72 73- (bool) initColorRampToolOverlayMembers 74{ 75 _colorRampToolOverlayPath_Outline = [[NSBezierPath bezierPath] retain]; 76 _colorRampToolOverlayPath_XMarks = [[NSBezierPath bezierPath] retain]; 77 78 if (!_colorRampToolOverlayPath_Outline || !_colorRampToolOverlayPath_XMarks) 79 { 80 goto ERROR; 81 } 82 83 return YES; 84 85ERROR: 86 return NO; 87} 88 89- (void) deallocColorRampToolOverlayMembers 90{ 91 [_colorRampToolOverlayPath_Outline release]; 92 _colorRampToolOverlayPath_Outline = nil; 93 94 [_colorRampToolOverlayPath_XMarks release]; 95 _colorRampToolOverlayPath_XMarks = nil; 96} 97 98- (void) setColorRampToolOverlayToMask: (NSBitmapImageRep *) maskBitmap 99 maskBounds: (NSRect) maskBounds 100{ 101 NSAffineTransform *canvasViewTransform; 102 NSRect outlinePathDisplayBounds, displayClippingBounds; 103 CGFloat outlinePathLineWidth, outlinePathLineHalfWidth, canvasDisplayOutsetAmount; 104 105 [self clearColorRampToolOverlay]; 106 107 if (![maskBitmap ppIsMaskBitmap]) 108 { 109 goto ERROR; 110 } 111 112 maskBounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect(maskBounds), 113 [maskBitmap ppFrameInPixels]); 114 115 if (NSIsEmptyRect(maskBounds)) 116 { 117 goto ERROR; 118 } 119 120 if (_zoomFactor < kMinZoomFactorToDrawOverlay) 121 { 122 return; 123 } 124 125 canvasViewTransform = [NSAffineTransform transform]; 126 127 if (!canvasViewTransform) 128 { 129 goto ERROR; 130 } 131 132 [canvasViewTransform translateXBy: _canvasDrawingOffset.x + 0.5f 133 yBy: _canvasDrawingOffset.y - 0.5f]; 134 135 [canvasViewTransform scaleBy: _zoomFactor]; 136 137 138 if (_hasSelectionOutline) 139 { 140 [_colorRampToolOverlayPath_XMarks 141 ppAppendXMarksForUnmaskedPixelsInMaskBitmap: maskBitmap 142 inBounds: maskBounds]; 143 144 [_colorRampToolOverlayPath_XMarks transformUsingAffineTransform: canvasViewTransform]; 145 } 146 147 [_colorRampToolOverlayPath_Outline appendBezierPathWithRect: maskBounds]; 148 149 if (maskBounds.size.width > 1.0) 150 { 151 [_colorRampToolOverlayPath_Outline 152 ppAppendPixelColumnSeparatorLinesInBounds: maskBounds]; 153 } 154 else if (maskBounds.size.height > 1.0) 155 { 156 [_colorRampToolOverlayPath_Outline ppAppendPixelRowSeparatorLinesInBounds: maskBounds]; 157 } 158 159 [_colorRampToolOverlayPath_Outline transformUsingAffineTransform: canvasViewTransform]; 160 161 outlinePathLineWidth = 162 (_zoomFactor >= kMinZoomFactorToDrawWideOutlines) ? 163 kOverlayPathLineWidth_WideOutline : kOverlayPathLineWidth_NarrowOutline; 164 165 outlinePathLineHalfWidth = outlinePathLineWidth / 2.0f; 166 167 [_colorRampToolOverlayPath_Outline setLineWidth: outlinePathLineWidth]; 168 169 outlinePathDisplayBounds = [_colorRampToolOverlayPath_Outline bounds]; 170 171 if (outlinePathLineHalfWidth > 0) 172 { 173 // outset outlinePathDisplayBounds to account for path's linewidth 174 outlinePathDisplayBounds = NSInsetRect(outlinePathDisplayBounds, 175 -outlinePathLineHalfWidth, 176 -outlinePathLineHalfWidth); 177 } 178 179 // allow the display bounds to extend past the canvas edges to account for the linewidth 180 181 canvasDisplayOutsetAmount = 1.0f + outlinePathLineHalfWidth; 182 183 displayClippingBounds = NSInsetRect(_offsetZoomedVisibleCanvasBounds, 184 -canvasDisplayOutsetAmount, 185 -canvasDisplayOutsetAmount); 186 187 _colorRampToolOverlayDisplayBounds = 188 PPGeometry_PixelBoundsCoveredByRect( 189 NSIntersectionRect(outlinePathDisplayBounds, displayClippingBounds)); 190 191 if (!NSIsEmptyRect(_colorRampToolOverlayDisplayBounds)) 192 { 193 _shouldDisplayColorRampToolOverlay = YES; 194 195 [self setNeedsDisplayInRect: _colorRampToolOverlayDisplayBounds]; 196 } 197 198 return; 199 200ERROR: 201 return; 202} 203 204- (void) clearColorRampToolOverlay 205{ 206 [_colorRampToolOverlayPath_Outline removeAllPoints]; 207 [_colorRampToolOverlayPath_XMarks removeAllPoints]; 208 209 if (_shouldDisplayColorRampToolOverlay) 210 { 211 [self setNeedsDisplayInRect: _colorRampToolOverlayDisplayBounds]; 212 } 213 214 _shouldDisplayColorRampToolOverlay = NO; 215 _colorRampToolOverlayDisplayBounds = NSZeroRect; 216} 217 218- (void) drawColorRampToolOverlay 219{ 220 if (!_shouldDisplayColorRampToolOverlay) 221 return; 222 223 if (![_colorRampToolOverlayPath_XMarks isEmpty] 224 && (_zoomFactor >= kMinZoomFactorToDrawXMarks)) 225 { 226 [gOverlayColor_XMarkHalo set]; 227 [_colorRampToolOverlayPath_XMarks setLineWidth: kOverlayPathLineWidth_XMarkHalo]; 228 [_colorRampToolOverlayPath_XMarks stroke]; 229 230 [gOverlayColor_XMarkLine set]; 231 [_colorRampToolOverlayPath_XMarks setLineWidth: kOverlayPathLineWidth_XMarkLine]; 232 [_colorRampToolOverlayPath_XMarks stroke]; 233 } 234 235 [gOverlayColor_Outline set]; 236 [_colorRampToolOverlayPath_Outline stroke]; 237} 238 239@end 240