From 8906ec7b2241237e3a656e48bff0d32875cb1b0f Mon Sep 17 00:00:00 2001 From: ericwa Date: Wed, 27 Jan 2010 22:43:21 +0000 Subject: [PATCH] Support for the padding box/content rect feature of Nine Patch theme tiles git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@29423 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 12 +++ Source/GSThemePrivate.h | 10 ++ Source/GSThemeTools.m | 198 ++++++++++++++++++++++++++++++---------- 3 files changed, 172 insertions(+), 48 deletions(-) diff --git a/ChangeLog b/ChangeLog index fbe69a2a7..04117d8d4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2010-01-27 Eric Wasylishen + + * Source/GSThemeTools.m: + * Source/GSThemePrivate.m: Added a contentRect feature to + GSDrawTiles. Previously, GSDrawTiles assumed that the rect the user + would draw in was exactly the center middle rect; i.e. the + return value of the xxStlyeFillRect: methods was the center middle + rect scaled to fit inside the drawing rect. + + Now this can be customized in Nine Patch tiles; see the diagrams at: + http://developer.android.com/guide/topics/graphics/2d-graphics.html#nine-patch + 2010-01-27 Fred Kiefer * Source/NSColor.m: (-hash): Don't use a dynamic union, as clang diff --git a/Source/GSThemePrivate.h b/Source/GSThemePrivate.h index 735b86e14..63095fff3 100644 --- a/Source/GSThemePrivate.h +++ b/Source/GSThemePrivate.h @@ -55,6 +55,9 @@ typedef enum { @public NSImage *images[9]; /** The tile images */ NSRect rects[9]; /** The rectangles to use when drawing */ + NSRect contentRect; /** Rectangle in which content should be + * drawn, normally rects[TileCM], but can + * be customized in the nine-patch format */ float scaleFactor; GSThemeFillStyle style; /** The default style for filling a rect */ } @@ -94,6 +97,13 @@ typedef enum { - (NSRect) fillRect: (NSRect)rect background: (NSColor*)color; +/** + * Returns the space available to draw content in when the tiles are + * drawn in the given rect, or NSZeroRect if the given rect is too small + * to draw the tiles in. + */ +- (NSRect) contentRectForRect: (NSRect)rect; + /* Style drawing methods */ - (NSRect) noneStyleFillRect: (NSRect)rect; diff --git a/Source/GSThemeTools.m b/Source/GSThemeTools.m index 33325fe7d..555215f3d 100644 --- a/Source/GSThemeTools.m +++ b/Source/GSThemeTools.m @@ -833,7 +833,73 @@ withRepeatedImage: (NSImage*)image rects[TileBL] = NSMakeRect(1, 1, x1 - 1, s.height - y2 - 2); rects[TileBM] = NSMakeRect(x1, 1, 1 + x2 - x1, s.height - y2 - 2); rects[TileBR] = NSMakeRect(x2 + 1, 1, s.width - x2 - 2, s.height - y2 - 2); - + + // Measure the content rect (the right and bottom edges of the nine-patch + // data) + + x1 = -1; + x2 = -1; + y1 = -1; + y2 = -1; + + for (i = 0; i < s.width; i++) + { + NSColor *pixelColor = [rep colorAtX: i y: s.height - 1]; + + [pixelColor getRed: &r green: &g blue: &b alpha: &a]; + if (a > 0 && x1 == -1) + { + x1 = i; + } + else if (a == 0 && x1 != -1) + { + x2 = i - 1; + break; + } + } + + for (i = 0; i < s.height; i++) + { + NSColor *pixelColor = [rep colorAtX: s.width - 1 y: i]; + + [pixelColor getRed: &r green: &g blue: &b alpha: &a]; + if (a > 0 && y1 == -1) + { + y1 = i; + } + else if (a == 0 && y1 != -1) + { + y2 = i - 1; + break; + } + } + + // Specifying the content rect part of the nine-patch image is optional + // ; if either the horizontal or vertical information is missing, use the + // geometry from rects[TileCM] + + if (x1 == -1) + { + contentRect.origin.x = rects[TileCM].origin.x; + contentRect.size.width = rects[TileCM].size.width; + } + else + { + contentRect.origin.x = x1; + contentRect.size.width = 1 + x2 - x1; + } + + if (y1 == -1) + { + contentRect.origin.y = rects[TileCM].origin.y; + contentRect.size.height = rects[TileCM].size.height; + } + else + { + contentRect.origin.y = s.height - y2 - 1; + contentRect.size.height = 1 + y2 - y1; + } + [self validateTilesSizeWithImage: image]; return self; } @@ -872,6 +938,12 @@ withRepeatedImage: (NSImage*)image rects[i].origin.y = 0; } } + + if (contentRect.origin.x < 0.0 || contentRect.origin.y < 0.0 + || contentRect.size.width <= 0.0 || contentRect.size.height <= 0.0) + { + contentRect = rects[TileCM]; + } } - (id) initWithImage: (NSImage*)image horizontal: (float)x vertical: (float)y @@ -892,6 +964,7 @@ withRepeatedImage: (NSImage*)image rects[TileBL] = NSMakeRect(0.0, 0.0, x, y); rects[TileBM] = NSMakeRect(x, 0.0, s.width - 2.0 * x, y); rects[TileBR] = NSMakeRect(s.width - x, 0.0, x, y); + contentRect = rects[TileCM]; style = GSThemeFillStyleNone; @@ -942,6 +1015,10 @@ withRepeatedImage: (NSImage*)image rects[i].origin.x *= scale; rects[i].origin.y *= scale; } + contentRect.size.height *= scale; + contentRect.size.width *= scale; + contentRect.origin.x *= scale; + contentRect.origin.y *= scale; } - (NSRect) fillRect: (NSRect)rect @@ -1000,18 +1077,76 @@ withRepeatedImage: (NSImage*)image return tsz; } +- (NSRect) contentRectForRect: (NSRect)rect +{ + NSRect contentRectParts[9]; + NSRect scaledContentRect; + int i; + float centerHScale, centerVScale; + + // Divide the content rect into 9 parts + for (i = 0; i < 9; i++) + { + contentRectParts[i] = NSIntersectionRect(contentRect, rects[i]); + } + + if (rects[TileCM].size.width > 0) + { + centerHScale = (rect.size.width - rects[TileCL].size.width - + rects[TileCR].size.width) / rects[TileCM].size.width; + } + else + { + centerHScale = 0; + } + + if (rects[TileCM].size.height > 0) + { + centerVScale = (rect.size.height - rects[TileCL].size.height - + rects[TileCR].size.height) / rects[TileCM].size.height; + } + else + { + centerVScale = 0; + } + + contentRectParts[TileTM].size.width *= centerHScale; + contentRectParts[TileCM].size.width *= centerHScale; + contentRectParts[TileBM].size.width *= centerHScale; + + contentRectParts[TileCL].size.height *= centerVScale; + contentRectParts[TileCM].size.height *= centerVScale; + contentRectParts[TileCR].size.height *= centerVScale; + + // Recalculate the origins of the top row and right column of the + // contentRectParts + + contentRectParts[TileTL].origin.y = contentRectParts[TileCL].origin.y + + contentRectParts[TileCL].size.height; + + contentRectParts[TileTM].origin.y = contentRectParts[TileTL].origin.y; + + contentRectParts[TileTR].origin.y = contentRectParts[TileTL].origin.y; + contentRectParts[TileTR].origin.x = contentRectParts[TileTM].origin.x + + contentRectParts[TileTM].size.width; + + contentRectParts[TileCR].origin.x = contentRectParts[TileTR].origin.x; + + contentRectParts[TileBR].origin.x = contentRectParts[TileTR].origin.x; + + // Return the union of the scaled contentRectParts + // NOTE: NSUnionRect ignores rects with width and height of 0 + scaledContentRect = NSZeroRect; + for (i = 0; i < 9; i++) + { + scaledContentRect = NSUnionRect(scaledContentRect, contentRectParts[i]); + } + return scaledContentRect; +} + - (NSRect) noneStyleFillRect: (NSRect)rect { - NSSize cls = rects[TileCL].size; - NSSize bms = rects[TileBM].size; - NSSize crs = rects[TileCR].size; - NSSize tms = rects[TileTM].size; - NSRect inFill = NSMakeRect ( - rect.origin.x + cls.width, - rect.origin.y + bms.height, - rect.size.width - cls.width - crs.width, - rect.size.height - bms.height - tms.height); - + NSRect inFill = [self contentRectForRect: rect]; [self repeatFillRect: rect]; [self drawCornersRect: rect]; return inFill; @@ -1021,17 +1156,8 @@ withRepeatedImage: (NSImage*)image { BOOL flipped = [[GSCurrentContext() focusView] isFlipped]; - NSSize cls = rects[TileCL].size; - NSSize bms = rects[TileBM].size; - NSSize crs = rects[TileCR].size; - NSSize tms = rects[TileTM].size; NSRect r = rects[TileCM]; - NSRect inFill = NSMakeRect ( - rect.origin.x + cls.width, - rect.origin.y + bms.height, - rect.size.width - cls.width - crs.width, - rect.size.height - bms.height - tms.height); - + NSRect inFill = [self contentRectForRect: rect]; [self repeatFillRect: rect]; [self drawCornersRect: rect]; @@ -1055,16 +1181,7 @@ withRepeatedImage: (NSImage*)image BOOL flipped = [[GSCurrentContext() focusView] isFlipped]; NSSize tsz = [self computeTotalTilesSize]; - NSSize cls = rects[TileCL].size; - NSSize bms = rects[TileBM].size; - NSSize crs = rects[TileCR].size; - NSSize tms = rects[TileTM].size; - NSRect inFill = NSMakeRect ( - rect.origin.x + cls.width, - rect.origin.y + bms.height, - rect.size.width - cls.width - crs.width, - rect.size.height - bms.height - tms.height); - + NSRect inFill = [self contentRectForRect: rect]; [self repeatFillRect: rect]; [self drawCornersRect: rect]; @@ -1083,16 +1200,7 @@ withRepeatedImage: (NSImage*)image { BOOL flipped = [[GSCurrentContext() focusView] isFlipped]; - NSSize cls = rects[TileCL].size; - NSSize bms = rects[TileBM].size; - NSSize crs = rects[TileCR].size; - NSSize tms = rects[TileTM].size; - - NSRect inFill = NSMakeRect ( - rect.origin.x + cls.width, - rect.origin.y + bms.height, - rect.size.width - cls.width - crs.width, - rect.size.height - bms.height - tms.height); + NSRect inFill = [self contentRectForRect: rect]; NSImage *im = [images[TileCM] copy]; NSRect r = rects[TileCM]; @@ -1135,14 +1243,8 @@ withRepeatedImage: (NSImage*)image NSSize tms = rects[TileTM].size; NSImage *img; NSRect imgRect; - NSRect inFill; - - inFill = NSMakeRect ( - rect.origin.x + cls.width, - rect.origin.y + bms.height, - rect.size.width - cls.width - crs.width, - rect.size.height - bms.height - tms.height); + NSRect inFill = [self contentRectForRect: rect]; [self scaleFillRect: rect]; [self drawCornersRect: rect];