diff --git a/QRichTextView/Assets/backcolor.png b/QRichTextView/Assets/backcolor.png
new file mode 100644
index 0000000..794d5c1
Binary files /dev/null and b/QRichTextView/Assets/backcolor.png differ
diff --git a/QRichTextView/Assets/bold.png b/QRichTextView/Assets/bold.png
new file mode 100644
index 0000000..3c21979
Binary files /dev/null and b/QRichTextView/Assets/bold.png differ
diff --git a/QRichTextView/Assets/bold@2x.png b/QRichTextView/Assets/bold@2x.png
new file mode 100644
index 0000000..e834f1d
Binary files /dev/null and b/QRichTextView/Assets/bold@2x.png differ
diff --git a/QRichTextView/Assets/bullist.png b/QRichTextView/Assets/bullist.png
new file mode 100644
index 0000000..cd84c95
Binary files /dev/null and b/QRichTextView/Assets/bullist.png differ
diff --git a/QRichTextView/Assets/bullist@2x.png b/QRichTextView/Assets/bullist@2x.png
new file mode 100644
index 0000000..7f90a64
Binary files /dev/null and b/QRichTextView/Assets/bullist@2x.png differ
diff --git a/QRichTextView/Assets/button.png b/QRichTextView/Assets/button.png
new file mode 100644
index 0000000..69c789d
Binary files /dev/null and b/QRichTextView/Assets/button.png differ
diff --git a/QRichTextView/Assets/buttonSelected.png b/QRichTextView/Assets/buttonSelected.png
new file mode 100644
index 0000000..6d2ced6
Binary files /dev/null and b/QRichTextView/Assets/buttonSelected.png differ
diff --git a/QRichTextView/Assets/buttoncenter.png b/QRichTextView/Assets/buttoncenter.png
new file mode 100644
index 0000000..64cc64e
Binary files /dev/null and b/QRichTextView/Assets/buttoncenter.png differ
diff --git a/QRichTextView/Assets/buttoncenterSelected.png b/QRichTextView/Assets/buttoncenterSelected.png
new file mode 100644
index 0000000..4b025fc
Binary files /dev/null and b/QRichTextView/Assets/buttoncenterSelected.png differ
diff --git a/QRichTextView/Assets/buttonleft.png b/QRichTextView/Assets/buttonleft.png
new file mode 100644
index 0000000..1a15aae
Binary files /dev/null and b/QRichTextView/Assets/buttonleft.png differ
diff --git a/QRichTextView/Assets/buttonleftSelected.png b/QRichTextView/Assets/buttonleftSelected.png
new file mode 100644
index 0000000..6486ed3
Binary files /dev/null and b/QRichTextView/Assets/buttonleftSelected.png differ
diff --git a/QRichTextView/Assets/buttonright.png b/QRichTextView/Assets/buttonright.png
new file mode 100644
index 0000000..6edab39
Binary files /dev/null and b/QRichTextView/Assets/buttonright.png differ
diff --git a/QRichTextView/Assets/buttonrightSelected.png b/QRichTextView/Assets/buttonrightSelected.png
new file mode 100644
index 0000000..e29ea61
Binary files /dev/null and b/QRichTextView/Assets/buttonrightSelected.png differ
diff --git a/QRichTextView/Assets/code.png b/QRichTextView/Assets/code.png
new file mode 100644
index 0000000..750878e
Binary files /dev/null and b/QRichTextView/Assets/code.png differ
diff --git a/QRichTextView/Assets/colors.jpg b/QRichTextView/Assets/colors.jpg
new file mode 100644
index 0000000..20e8f2c
Binary files /dev/null and b/QRichTextView/Assets/colors.jpg differ
diff --git a/QRichTextView/Assets/dropDownTriangle.png b/QRichTextView/Assets/dropDownTriangle.png
new file mode 100644
index 0000000..0657bc8
Binary files /dev/null and b/QRichTextView/Assets/dropDownTriangle.png differ
diff --git a/QRichTextView/Assets/dropDownTriangle@2x.png b/QRichTextView/Assets/dropDownTriangle@2x.png
new file mode 100644
index 0000000..164c501
Binary files /dev/null and b/QRichTextView/Assets/dropDownTriangle@2x.png differ
diff --git a/QRichTextView/Assets/email.png b/QRichTextView/Assets/email.png
new file mode 100644
index 0000000..cc79cab
Binary files /dev/null and b/QRichTextView/Assets/email.png differ
diff --git a/QRichTextView/Assets/file.png b/QRichTextView/Assets/file.png
new file mode 100644
index 0000000..83ed38c
Binary files /dev/null and b/QRichTextView/Assets/file.png differ
diff --git a/QRichTextView/Assets/firstLineIndent.png b/QRichTextView/Assets/firstLineIndent.png
new file mode 100644
index 0000000..14ce345
Binary files /dev/null and b/QRichTextView/Assets/firstLineIndent.png differ
diff --git a/QRichTextView/Assets/firstLineIndent@2x.png b/QRichTextView/Assets/firstLineIndent@2x.png
new file mode 100644
index 0000000..c1da40b
Binary files /dev/null and b/QRichTextView/Assets/firstLineIndent@2x.png differ
diff --git a/QRichTextView/Assets/forecolor.png b/QRichTextView/Assets/forecolor.png
new file mode 100644
index 0000000..225a29a
Binary files /dev/null and b/QRichTextView/Assets/forecolor.png differ
diff --git a/QRichTextView/Assets/image.png b/QRichTextView/Assets/image.png
new file mode 100644
index 0000000..2c29b36
Binary files /dev/null and b/QRichTextView/Assets/image.png differ
diff --git a/QRichTextView/Assets/indent.png b/QRichTextView/Assets/indent.png
new file mode 100644
index 0000000..e0f5e90
Binary files /dev/null and b/QRichTextView/Assets/indent.png differ
diff --git a/QRichTextView/Assets/indent@2x.png b/QRichTextView/Assets/indent@2x.png
new file mode 100644
index 0000000..3479634
Binary files /dev/null and b/QRichTextView/Assets/indent@2x.png differ
diff --git a/QRichTextView/Assets/italic.png b/QRichTextView/Assets/italic.png
new file mode 100644
index 0000000..f9982f1
Binary files /dev/null and b/QRichTextView/Assets/italic.png differ
diff --git a/QRichTextView/Assets/italic@2x.png b/QRichTextView/Assets/italic@2x.png
new file mode 100644
index 0000000..ccf7b18
Binary files /dev/null and b/QRichTextView/Assets/italic@2x.png differ
diff --git a/QRichTextView/Assets/justifycenter.png b/QRichTextView/Assets/justifycenter.png
new file mode 100644
index 0000000..bd76f35
Binary files /dev/null and b/QRichTextView/Assets/justifycenter.png differ
diff --git a/QRichTextView/Assets/justifycenter@2x.png b/QRichTextView/Assets/justifycenter@2x.png
new file mode 100644
index 0000000..8232942
Binary files /dev/null and b/QRichTextView/Assets/justifycenter@2x.png differ
diff --git a/QRichTextView/Assets/justifyfull.png b/QRichTextView/Assets/justifyfull.png
new file mode 100644
index 0000000..ee62452
Binary files /dev/null and b/QRichTextView/Assets/justifyfull.png differ
diff --git a/QRichTextView/Assets/justifyfull@2x.png b/QRichTextView/Assets/justifyfull@2x.png
new file mode 100644
index 0000000..2706960
Binary files /dev/null and b/QRichTextView/Assets/justifyfull@2x.png differ
diff --git a/QRichTextView/Assets/justifyleft.png b/QRichTextView/Assets/justifyleft.png
new file mode 100644
index 0000000..5180469
Binary files /dev/null and b/QRichTextView/Assets/justifyleft.png differ
diff --git a/QRichTextView/Assets/justifyleft@2x.png b/QRichTextView/Assets/justifyleft@2x.png
new file mode 100644
index 0000000..ebaf881
Binary files /dev/null and b/QRichTextView/Assets/justifyleft@2x.png differ
diff --git a/QRichTextView/Assets/justifyright.png b/QRichTextView/Assets/justifyright.png
new file mode 100644
index 0000000..e281ef4
Binary files /dev/null and b/QRichTextView/Assets/justifyright.png differ
diff --git a/QRichTextView/Assets/justifyright@2x.png b/QRichTextView/Assets/justifyright@2x.png
new file mode 100644
index 0000000..e1401ed
Binary files /dev/null and b/QRichTextView/Assets/justifyright@2x.png differ
diff --git a/QRichTextView/Assets/link.png b/QRichTextView/Assets/link.png
new file mode 100644
index 0000000..b261c63
Binary files /dev/null and b/QRichTextView/Assets/link.png differ
diff --git a/QRichTextView/Assets/numlist.png b/QRichTextView/Assets/numlist.png
new file mode 100644
index 0000000..d6b1d11
Binary files /dev/null and b/QRichTextView/Assets/numlist.png differ
diff --git a/QRichTextView/Assets/numlist@2x.png b/QRichTextView/Assets/numlist@2x.png
new file mode 100644
index 0000000..98b9d4c
Binary files /dev/null and b/QRichTextView/Assets/numlist@2x.png differ
diff --git a/QRichTextView/Assets/outdent.png b/QRichTextView/Assets/outdent.png
new file mode 100644
index 0000000..50ef607
Binary files /dev/null and b/QRichTextView/Assets/outdent.png differ
diff --git a/QRichTextView/Assets/outdent@2x.png b/QRichTextView/Assets/outdent@2x.png
new file mode 100644
index 0000000..38afd72
Binary files /dev/null and b/QRichTextView/Assets/outdent@2x.png differ
diff --git a/QRichTextView/Assets/popoverArrowDown.png b/QRichTextView/Assets/popoverArrowDown.png
new file mode 100755
index 0000000..b632256
Binary files /dev/null and b/QRichTextView/Assets/popoverArrowDown.png differ
diff --git a/QRichTextView/Assets/popoverArrowDown@2x.png b/QRichTextView/Assets/popoverArrowDown@2x.png
new file mode 100755
index 0000000..8b79116
Binary files /dev/null and b/QRichTextView/Assets/popoverArrowDown@2x.png differ
diff --git a/QRichTextView/Assets/popoverArrowDownSimple.png b/QRichTextView/Assets/popoverArrowDownSimple.png
new file mode 100755
index 0000000..ddae902
Binary files /dev/null and b/QRichTextView/Assets/popoverArrowDownSimple.png differ
diff --git a/QRichTextView/Assets/popoverArrowLeft.png b/QRichTextView/Assets/popoverArrowLeft.png
new file mode 100755
index 0000000..d55ef2b
Binary files /dev/null and b/QRichTextView/Assets/popoverArrowLeft.png differ
diff --git a/QRichTextView/Assets/popoverArrowLeft@2x.png b/QRichTextView/Assets/popoverArrowLeft@2x.png
new file mode 100755
index 0000000..f9d055a
Binary files /dev/null and b/QRichTextView/Assets/popoverArrowLeft@2x.png differ
diff --git a/QRichTextView/Assets/popoverArrowLeftSimple.png b/QRichTextView/Assets/popoverArrowLeftSimple.png
new file mode 100755
index 0000000..adc4a8a
Binary files /dev/null and b/QRichTextView/Assets/popoverArrowLeftSimple.png differ
diff --git a/QRichTextView/Assets/popoverArrowRight.png b/QRichTextView/Assets/popoverArrowRight.png
new file mode 100755
index 0000000..f549522
Binary files /dev/null and b/QRichTextView/Assets/popoverArrowRight.png differ
diff --git a/QRichTextView/Assets/popoverArrowRight@2x.png b/QRichTextView/Assets/popoverArrowRight@2x.png
new file mode 100755
index 0000000..84af6f5
Binary files /dev/null and b/QRichTextView/Assets/popoverArrowRight@2x.png differ
diff --git a/QRichTextView/Assets/popoverArrowRightSimple.png b/QRichTextView/Assets/popoverArrowRightSimple.png
new file mode 100755
index 0000000..b3ebfe3
Binary files /dev/null and b/QRichTextView/Assets/popoverArrowRightSimple.png differ
diff --git a/QRichTextView/Assets/popoverArrowUp.png b/QRichTextView/Assets/popoverArrowUp.png
new file mode 100755
index 0000000..14adae0
Binary files /dev/null and b/QRichTextView/Assets/popoverArrowUp.png differ
diff --git a/QRichTextView/Assets/popoverArrowUp@2x.png b/QRichTextView/Assets/popoverArrowUp@2x.png
new file mode 100755
index 0000000..40428f5
Binary files /dev/null and b/QRichTextView/Assets/popoverArrowUp@2x.png differ
diff --git a/QRichTextView/Assets/popoverArrowUpSimple.png b/QRichTextView/Assets/popoverArrowUpSimple.png
new file mode 100755
index 0000000..099d54f
Binary files /dev/null and b/QRichTextView/Assets/popoverArrowUpSimple.png differ
diff --git a/QRichTextView/Assets/popoverBg.png b/QRichTextView/Assets/popoverBg.png
new file mode 100755
index 0000000..8fb6754
Binary files /dev/null and b/QRichTextView/Assets/popoverBg.png differ
diff --git a/QRichTextView/Assets/popoverBg@2x.png b/QRichTextView/Assets/popoverBg@2x.png
new file mode 100755
index 0000000..e1e575b
Binary files /dev/null and b/QRichTextView/Assets/popoverBg@2x.png differ
diff --git a/QRichTextView/Assets/popoverBgSimple.png b/QRichTextView/Assets/popoverBgSimple.png
new file mode 100755
index 0000000..3cdf457
Binary files /dev/null and b/QRichTextView/Assets/popoverBgSimple.png differ
diff --git a/QRichTextView/Assets/redo.png b/QRichTextView/Assets/redo.png
new file mode 100644
index 0000000..62d04c4
Binary files /dev/null and b/QRichTextView/Assets/redo.png differ
diff --git a/QRichTextView/Assets/removeformat.png b/QRichTextView/Assets/removeformat.png
new file mode 100644
index 0000000..1a2b6dc
Binary files /dev/null and b/QRichTextView/Assets/removeformat.png differ
diff --git a/QRichTextView/Assets/strikethrough.png b/QRichTextView/Assets/strikethrough.png
new file mode 100644
index 0000000..7f83663
Binary files /dev/null and b/QRichTextView/Assets/strikethrough.png differ
diff --git a/QRichTextView/Assets/strikethrough@2x.png b/QRichTextView/Assets/strikethrough@2x.png
new file mode 100644
index 0000000..9d93c53
Binary files /dev/null and b/QRichTextView/Assets/strikethrough@2x.png differ
diff --git a/QRichTextView/Assets/underline.png b/QRichTextView/Assets/underline.png
new file mode 100644
index 0000000..627f8d2
Binary files /dev/null and b/QRichTextView/Assets/underline.png differ
diff --git a/QRichTextView/Assets/underline@2x.png b/QRichTextView/Assets/underline@2x.png
new file mode 100644
index 0000000..502a40f
Binary files /dev/null and b/QRichTextView/Assets/underline@2x.png differ
diff --git a/QRichTextView/Assets/undo.png b/QRichTextView/Assets/undo.png
new file mode 100644
index 0000000..2ab62b6
Binary files /dev/null and b/QRichTextView/Assets/undo.png differ
diff --git a/QRichTextView/Assets/unlink.png b/QRichTextView/Assets/unlink.png
new file mode 100644
index 0000000..a5913e0
Binary files /dev/null and b/QRichTextView/Assets/unlink.png differ
diff --git a/QRichTextView/Classes/NSAttributedString+RichTextEditor.h b/QRichTextView/Classes/NSAttributedString+RichTextEditor.h
new file mode 100644
index 0000000..423f99c
--- /dev/null
+++ b/QRichTextView/Classes/NSAttributedString+RichTextEditor.h
@@ -0,0 +1,37 @@
+//
+// NSAttributedString+RichTextEditor.h
+// RichTextEdtor
+//
+// Created by Aryan Gh on 7/21/13.
+// Copyright (c) 2013 Aryan Ghassemi. All rights reserved.
+//
+// https://github.com/aryaxt/iOS-Rich-Text-Editor
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import
+#import "UIFont+RichTextEditor.h"
+
+@interface NSAttributedString (RichTextEditor)
+
+- (NSRange)firstParagraphRangeFromTextRange:(NSRange)range;
+- (NSArray *)rangeOfParagraphsFromTextRange:(NSRange)textRange;
+- (NSString *)htmlString;
+
+@end
diff --git a/QRichTextView/Classes/NSAttributedString+RichTextEditor.m b/QRichTextView/Classes/NSAttributedString+RichTextEditor.m
new file mode 100644
index 0000000..15052e2
--- /dev/null
+++ b/QRichTextView/Classes/NSAttributedString+RichTextEditor.m
@@ -0,0 +1,220 @@
+//
+// NSAttributedString+RichTextEditor.m
+// RichTextEdtor
+//
+// Created by Aryan Gh on 7/21/13.
+// Copyright (c) 2013 Aryan Ghassemi. All rights reserved.
+//
+// https://github.com/aryaxt/iOS-Rich-Text-Editor
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import "NSAttributedString+RichTextEditor.h"
+
+@implementation NSAttributedString (RichTextEditor)
+
+#pragma mark - Public MEthods -
+
+- (NSRange)firstParagraphRangeFromTextRange:(NSRange)range
+{
+ NSInteger start = -1;
+ NSInteger end = -1;
+ NSInteger length = 0;
+
+ NSInteger startingRange = (range.location == self.string.length || [self.string characterAtIndex:range.location] == '\n') ?
+ range.location-1 :
+ range.location;
+
+ for (int i=startingRange ; i>=0 ; i--)
+ {
+ char c = [self.string characterAtIndex:i];
+ if (c == '\n')
+ {
+ start = i+1;
+ break;
+ }
+ }
+
+ start = (start == -1) ? 0 : start;
+
+ NSInteger moveForwardIndex = (range.location > start) ? range.location : start;
+
+ for (int i=moveForwardIndex; i<= self.string.length-1 ; i++)
+ {
+ char c = [self.string characterAtIndex:i];
+ if (c == '\n')
+ {
+ end = i;
+ break;
+ }
+ }
+
+ end = (end == -1) ? self.string.length : end;
+ length = end - start;
+
+ return NSMakeRange(start, length);
+}
+
+- (NSArray *)rangeOfParagraphsFromTextRange:(NSRange)textRange
+{
+ NSMutableArray *paragraphRanges = [NSMutableArray array];
+ NSInteger rangeStartIndex = textRange.location;
+
+ while (true)
+ {
+ NSRange range = [self firstParagraphRangeFromTextRange:NSMakeRange(rangeStartIndex, 0)];
+ rangeStartIndex = range.location + range.length + 1;
+
+ [paragraphRanges addObject:[NSValue valueWithRange:range]];
+
+ if (range.location + range.length >= textRange.location + textRange.length)
+ break;
+ }
+
+ return paragraphRanges;
+}
+
+- (NSString *)htmlString
+{
+ NSMutableString *htmlString = [NSMutableString string];
+ NSArray *paragraphRanges = [self rangeOfParagraphsFromTextRange:NSMakeRange(0, self.string.length-1)];
+
+ for (int i=0 ; i 0)
+ [htmlString appendFormat:@"text-indent:%.0fpx; ", paragraphStyle.firstLineHeadIndent - paragraphStyle.headIndent];
+
+ if (paragraphStyle.headIndent > 0)
+ [htmlString appendFormat:@"margin-left:%.0fpx; ", paragraphStyle.headIndent];
+
+
+ [htmlString appendString:@" \">"];
+
+ [self enumerateAttributesInRange:range
+ options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
+ usingBlock:^(NSDictionary *dictionary, NSRange range, BOOL *stop){
+
+ NSMutableString *fontString = [NSMutableString string];
+ UIFont *font = [dictionary objectForKey:NSFontAttributeName];
+ UIColor *foregroundColor = [dictionary objectForKey:NSForegroundColorAttributeName];
+ UIColor *backGroundColor = [dictionary objectForKey:NSBackgroundColorAttributeName];
+ NSNumber *underline = [dictionary objectForKey:NSUnderlineStyleAttributeName];
+ BOOL hasUnderline = (!underline || underline.intValue == NSUnderlineStyleNone) ? NO :YES;
+ NSNumber *strikeThrough = [dictionary objectForKey:NSStrikethroughStyleAttributeName];
+ BOOL hasStrikeThrough = (!strikeThrough || strikeThrough.intValue == NSUnderlineStyleNone) ? NO :YES;
+
+ [fontString appendFormat:@""];
+ [fontString appendString:[[self.string substringFromIndex:range.location] substringToIndex:range.length]];
+ [fontString appendString:@""];
+
+ if ([font isBold])
+ {
+ [fontString insertString:@"" atIndex:0];
+ [fontString insertString:@"" atIndex:fontString.length];
+ }
+
+ if ([font isItalic])
+ {
+ [fontString insertString:@"" atIndex:0];
+ [fontString insertString:@"" atIndex:fontString.length];
+ }
+
+ if (hasUnderline)
+ {
+ [fontString insertString:@"" atIndex:0];
+ [fontString insertString:@"" atIndex:fontString.length];
+ }
+
+ if (hasStrikeThrough)
+ {
+ [fontString insertString:@"" atIndex:0];
+ [fontString insertString:@"" atIndex:fontString.length];
+ }
+
+
+ [htmlString appendString:fontString];
+ }];
+
+ [htmlString appendString:@"
"];
+ }
+
+ return htmlString;
+}
+
+#pragma mark - Helper Methods -
+
+- (NSString *)htmlTextAlignmentString:(NSTextAlignment)textAlignment
+{
+ switch (textAlignment)
+ {
+ case NSTextAlignmentLeft:
+ return @"left";
+
+ case NSTextAlignmentCenter:
+ return @"center";
+
+ case NSTextAlignmentRight:
+ return @"right";
+
+ case NSTextAlignmentJustified:
+ return @"justify";
+
+ default:
+ return nil;
+ }
+}
+
+- (NSString *)htmlRgbColor:(UIColor *)color
+{
+ CGFloat red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0;
+ [color getRed:&red green:&green blue:&blue alpha:&alpha];
+ return [NSString stringWithFormat:@"rgb(%d,%d,%d)",(int)(red*255.0), (int)(green*255.0), (int)(blue*255.0)];
+}
+
+@end
diff --git a/QRichTextView/Classes/UIBarButtonItem+WEPopover.h b/QRichTextView/Classes/UIBarButtonItem+WEPopover.h
new file mode 100755
index 0000000..4cf59bd
--- /dev/null
+++ b/QRichTextView/Classes/UIBarButtonItem+WEPopover.h
@@ -0,0 +1,18 @@
+/*
+ * UIBarButtonItem+WEPopover.h
+ * WEPopover
+ *
+ * Created by Werner Altewischer on 07/05/11.
+ * Copyright 2010 Werner IT Consultancy. All rights reserved.
+ *
+ */
+
+#import
+#import
+
+@interface UIBarButtonItem(WEPopover)
+
+- (CGRect)frameInView:(UIView *)v;
+- (UIView *)superview;
+
+@end
diff --git a/QRichTextView/Classes/UIBarButtonItem+WEPopover.m b/QRichTextView/Classes/UIBarButtonItem+WEPopover.m
new file mode 100755
index 0000000..52b13d2
--- /dev/null
+++ b/QRichTextView/Classes/UIBarButtonItem+WEPopover.m
@@ -0,0 +1,46 @@
+/*
+ * UIBarButtonItem+WEPopover.m
+ * WEPopover
+ *
+ * Created by Werner Altewischer on 07/05/11.
+ * Copyright 2010 Werner IT Consultancy. All rights reserved.
+ *
+ */
+
+#import "UIBarButtonItem+WEPopover.h"
+
+@implementation UIBarButtonItem(WEPopover)
+
+- (CGRect)frameInView:(UIView *)v {
+
+ UIView *theView = self.customView;
+ if (!theView && [self respondsToSelector:@selector(view)]) {
+ theView = [self performSelector:@selector(view)];
+ }
+
+ UIView *parentView = theView.superview;
+ NSArray *subviews = parentView.subviews;
+
+ NSUInteger indexOfView = [subviews indexOfObject:theView];
+ NSUInteger subviewCount = subviews.count;
+
+ if (subviewCount > 0 && indexOfView != NSNotFound) {
+ UIView *button = [parentView.subviews objectAtIndex:indexOfView];
+ return [button convertRect:button.bounds toView:v];
+ } else {
+ return CGRectZero;
+ }
+}
+
+- (UIView *)superview {
+
+ UIView *theView = self.customView;
+ if (!theView && [self respondsToSelector:@selector(view)]) {
+ theView = [self performSelector:@selector(view)];
+ }
+
+ UIView *parentView = theView.superview;
+ return parentView;
+}
+
+@end
diff --git a/QRichTextView/Classes/UIFont+RichTextEditor.h b/QRichTextView/Classes/UIFont+RichTextEditor.h
new file mode 100644
index 0000000..a56acf5
--- /dev/null
+++ b/QRichTextView/Classes/UIFont+RichTextEditor.h
@@ -0,0 +1,40 @@
+//
+// UIFont+RichTextEditor.h
+// RichTextEdtor
+//
+// Created by Aryan Gh on 7/21/13.
+// Copyright (c) 2013 Aryan Ghassemi. All rights reserved.
+//
+// https://github.com/aryaxt/iOS-Rich-Text-Editor
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import
+#import
+
+@interface UIFont (RichTextEditor)
+
++ (NSString *)postscriptNameFromFullName:(NSString *)fullName;
++ (UIFont *)fontWithName:(NSString *)name size:(CGFloat)size boldTrait:(BOOL)isBold italicTrait:(BOOL)isItalic;
+- (UIFont *)fontWithBoldTrait:(BOOL)bold italicTrait:(BOOL)italic andSize:(CGFloat)size;
+- (UIFont *)fontWithBoldTrait:(BOOL)bold andItalicTrait:(BOOL)italic;
+- (BOOL)isBold;
+- (BOOL)isItalic;
+
+@end
diff --git a/QRichTextView/Classes/UIFont+RichTextEditor.m b/QRichTextView/Classes/UIFont+RichTextEditor.m
new file mode 100644
index 0000000..10b95ce
--- /dev/null
+++ b/QRichTextView/Classes/UIFont+RichTextEditor.m
@@ -0,0 +1,103 @@
+//
+// UIFont+RichTextEditor.m
+// RichTextEdtor
+//
+// Created by Aryan Gh on 7/21/13.
+// Copyright (c) 2013 Aryan Ghassemi. All rights reserved.
+//
+// https://github.com/aryaxt/iOS-Rich-Text-Editor
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import "UIFont+RichTextEditor.h"
+
+@implementation UIFont (RichTextEditor)
+
++ (NSString *)postscriptNameFromFullName:(NSString *)fullName
+{
+ UIFont *font = [UIFont fontWithName:fullName size:1];
+ return (__bridge NSString *)(CTFontCopyPostScriptName((__bridge CTFontRef)(font)));
+}
+
++ (UIFont *)fontWithName:(NSString *)name size:(CGFloat)size boldTrait:(BOOL)isBold italicTrait:(BOOL)isItalic
+{
+ NSString *postScriptName = [UIFont postscriptNameFromFullName:name];
+
+ CTFontSymbolicTraits traits = 0;
+ CTFontRef newFontRef;
+ CTFontRef fontWithoutTrait = CTFontCreateWithName((__bridge CFStringRef)(postScriptName), size, NULL);
+
+ if (isItalic)
+ traits |= kCTFontItalicTrait;
+
+ if (isBold)
+ traits |= kCTFontBoldTrait;
+
+ if (traits == 0)
+ {
+ newFontRef= CTFontCreateCopyWithAttributes(fontWithoutTrait, 0.0, NULL, NULL);
+ }
+ else
+ {
+ newFontRef = CTFontCreateCopyWithSymbolicTraits(fontWithoutTrait, 0.0, NULL, traits, traits);
+ }
+
+ if (newFontRef)
+ {
+ NSString *fontNameKey = (__bridge NSString *)(CTFontCopyName(newFontRef, kCTFontPostScriptNameKey));
+ return [UIFont fontWithName:fontNameKey size:CTFontGetSize(newFontRef)];
+ }
+
+ return nil;
+}
+
+- (UIFont *)fontWithBoldTrait:(BOOL)bold italicTrait:(BOOL)italic andSize:(CGFloat)size
+{
+ CTFontRef fontRef = (__bridge CTFontRef)self;
+ NSString *familyName = (__bridge NSString *)(CTFontCopyName(fontRef, kCTFontFamilyNameKey));
+ NSString *postScriptName = [UIFont postscriptNameFromFullName:familyName];
+ return [[self class] fontWithName:postScriptName size:size boldTrait:bold italicTrait:italic];
+}
+
+- (UIFont *)fontWithBoldTrait:(BOOL)bold andItalicTrait:(BOOL)italic
+{
+ return [self fontWithBoldTrait:bold italicTrait:italic andSize:self.pointSize];
+}
+
+- (BOOL)isBold
+{
+ CTFontSymbolicTraits trait = CTFontGetSymbolicTraits((__bridge CTFontRef)self);
+
+ if ((trait & kCTFontTraitBold) == kCTFontTraitBold)
+ return YES;
+
+ return NO;
+}
+
+- (BOOL)isItalic
+{
+ CTFontSymbolicTraits trait = CTFontGetSymbolicTraits((__bridge CTFontRef)self);
+
+ if ((trait & kCTFontTraitItalic) == kCTFontTraitItalic)
+ return YES;
+
+ return NO;
+}
+
+@end
diff --git a/QRichTextView/Classes/UIView+RichTextEditor.h b/QRichTextView/Classes/UIView+RichTextEditor.h
new file mode 100644
index 0000000..4c00b28
--- /dev/null
+++ b/QRichTextView/Classes/UIView+RichTextEditor.h
@@ -0,0 +1,36 @@
+//
+// UIView+RichTextEditor.h
+// RichTextEdtor
+//
+// Created by Aryan Gh on 7/21/13.
+// Copyright (c) 2013 Aryan Ghassemi. All rights reserved.
+//
+// https://github.com/aryaxt/iOS-Rich-Text-Editor
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import
+#import
+
+@interface UIView (RichTextEditor)
+
+- (UIColor *)colorOfPoint:(CGPoint)point;
+- (UIViewController *)firstAvailableViewController;
+
+@end
diff --git a/QRichTextView/Classes/UIView+RichTextEditor.m b/QRichTextView/Classes/UIView+RichTextEditor.m
new file mode 100644
index 0000000..831cefe
--- /dev/null
+++ b/QRichTextView/Classes/UIView+RichTextEditor.m
@@ -0,0 +1,72 @@
+//
+// UIView+RichTextEditor.m
+// RichTextEdtor
+//
+// Created by Aryan Gh on 7/21/13.
+// Copyright (c) 2013 Aryan Ghassemi. All rights reserved.
+//
+// https://github.com/aryaxt/iOS-Rich-Text-Editor
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import "UIView+RichTextEditor.h"
+
+@implementation UIView (RichTextEditor)
+
+- (UIColor *)colorOfPoint:(CGPoint)point
+{
+ unsigned char pixel[4] = {0};
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+ CGContextRef context = CGBitmapContextCreate(pixel, 1, 1, 8, 4, colorSpace, (uint32_t)kCGImageAlphaPremultipliedLast);
+
+ CGContextTranslateCTM(context, -point.x, -point.y);
+
+ [self.layer renderInContext:context];
+
+ CGContextRelease(context);
+ CGColorSpaceRelease(colorSpace);
+ UIColor *color = [UIColor colorWithRed:pixel[0]/255.0 green:pixel[1]/255.0 blue:pixel[2]/255.0 alpha:pixel[3]/255.0];
+
+ return color;
+}
+
+- (UIViewController *)firstAvailableViewController
+{
+ return (UIViewController *)[self traverseResponderChainForUIViewController];
+}
+
+- (id)traverseResponderChainForUIViewController
+{
+ id nextResponder = [self nextResponder];
+
+ if ([nextResponder isKindOfClass:[UIViewController class]])
+ {
+ return nextResponder;
+ }
+ else if ([nextResponder isKindOfClass:[UIView class]])
+ {
+ return [nextResponder traverseResponderChainForUIViewController];
+ }
+ else
+ {
+ return nil;
+ }
+}
+
+@end
diff --git a/QRichTextView/Classes/WEPopoverContainerView.h b/QRichTextView/Classes/WEPopoverContainerView.h
new file mode 100755
index 0000000..ffe32a6
--- /dev/null
+++ b/QRichTextView/Classes/WEPopoverContainerView.h
@@ -0,0 +1,100 @@
+//
+// WEPopoverContainerView.h
+// WEPopover
+//
+// Created by Werner Altewischer on 02/09/10.
+// Copyright 2010 Werner IT Consultancy. All rights reserved.
+//
+
+#import
+#import
+
+/**
+ * @brief Properties for the container view determining the area where the actual content view can/may be displayed. Also Images can be supplied for the arrow images and background.
+ */
+@interface WEPopoverContainerViewProperties : NSObject
+{
+ NSString *bgImageName;
+ NSString *upArrowImageName;
+ NSString *downArrowImageName;
+ NSString *leftArrowImageName;
+ NSString *rightArrowImageName;
+ CGFloat leftBgMargin;
+ CGFloat rightBgMargin;
+ CGFloat topBgMargin;
+ CGFloat bottomBgMargin;
+ NSInteger topBgCapSize;
+ NSInteger leftBgCapSize;
+ CGFloat arrowMargin;
+}
+
+@property(nonatomic, retain) NSString *bgImageName;
+@property(nonatomic, retain) NSString *upArrowImageName;
+@property(nonatomic, retain) NSString *downArrowImageName;
+@property(nonatomic, retain) NSString *leftArrowImageName;
+@property(nonatomic, retain) NSString *rightArrowImageName;
+@property(nonatomic, assign) CGFloat leftBgMargin;
+@property(nonatomic, assign) CGFloat rightBgMargin;
+@property(nonatomic, assign) CGFloat topBgMargin;
+@property(nonatomic, assign) CGFloat bottomBgMargin;
+@property(nonatomic, assign) CGFloat leftContentMargin;
+@property(nonatomic, assign) CGFloat rightContentMargin;
+@property(nonatomic, assign) CGFloat topContentMargin;
+@property(nonatomic, assign) CGFloat bottomContentMargin;
+@property(nonatomic, assign) NSInteger topBgCapSize;
+@property(nonatomic, assign) NSInteger leftBgCapSize;
+@property(nonatomic, assign) CGFloat arrowMargin;
+
+@end
+
+@class WEPopoverContainerView;
+
+/**
+ * @brief Container/background view for displaying a popover view.
+ */
+@interface WEPopoverContainerView : UIView {
+ UIImage *bgImage;
+ UIImage *arrowImage;
+
+ WEPopoverContainerViewProperties *properties;
+
+ UIPopoverArrowDirection arrowDirection;
+
+ CGRect arrowRect;
+ CGRect bgRect;
+ CGPoint offset;
+ CGPoint arrowOffset;
+
+ CGSize correctedSize;
+ UIView *contentView;
+}
+
+/**
+ * @brief The current arrow direction for the popover.
+ */
+@property (nonatomic, readonly) UIPopoverArrowDirection arrowDirection;
+
+/**
+ * @brief The content view being displayed.
+ */
+@property (nonatomic, retain) UIView *contentView;
+
+/**
+ * @brief Initializes the position of the popover with a size, anchor rect, display area and permitted arrow directions and optionally the properties.
+ * If the last is not supplied the defaults are taken (requires images to be present in bundle representing a black rounded background with partial transparency).
+ */
+- (id)initWithSize:(CGSize)theSize
+ anchorRect:(CGRect)anchorRect
+ displayArea:(CGRect)displayArea
+permittedArrowDirections:(UIPopoverArrowDirection)permittedArrowDirections
+ properties:(WEPopoverContainerViewProperties *)properties;
+
+/**
+ * @brief To update the position of the popover with a new anchor rect, display area and permitted arrow directions
+ */
+- (void)updatePositionWithSize:(CGSize)theSize
+ anchorRect:(CGRect)anchorRect
+ displayArea:(CGRect)displayArea
+ permittedArrowDirections:(UIPopoverArrowDirection)permittedArrowDirections;
+
+@end
diff --git a/QRichTextView/Classes/WEPopoverContainerView.m b/QRichTextView/Classes/WEPopoverContainerView.m
new file mode 100755
index 0000000..d037050
--- /dev/null
+++ b/QRichTextView/Classes/WEPopoverContainerView.m
@@ -0,0 +1,367 @@
+//
+// WEPopoverContainerViewProperties.m
+// WEPopover
+//
+// Created by Werner Altewischer on 02/09/10.
+// Copyright 2010 Werner IT Consultancy. All rights reserved.
+//
+
+#import "WEPopoverContainerView.h"
+
+@implementation WEPopoverContainerViewProperties
+
+@synthesize bgImageName, upArrowImageName, downArrowImageName, leftArrowImageName, rightArrowImageName, topBgMargin, bottomBgMargin, leftBgMargin, rightBgMargin, topBgCapSize, leftBgCapSize;
+@synthesize leftContentMargin, rightContentMargin, topContentMargin, bottomContentMargin, arrowMargin;
+
+//- (void)dealloc {
+// self.bgImageName = nil;
+// self.upArrowImageName = nil;
+// self.downArrowImageName = nil;
+// self.leftArrowImageName = nil;
+// self.rightArrowImageName = nil;
+// [super dealloc];
+//}
+
+@end
+
+@interface WEPopoverContainerView(Private)
+
+- (void)determineGeometryForSize:(CGSize)theSize anchorRect:(CGRect)anchorRect displayArea:(CGRect)displayArea permittedArrowDirections:(UIPopoverArrowDirection)permittedArrowDirections;
+- (CGRect)contentRect;
+- (CGSize)contentSize;
+- (void)setProperties:(WEPopoverContainerViewProperties *)props;
+- (void)initFrame;
+
+@end
+
+@implementation WEPopoverContainerView
+
+@synthesize arrowDirection, contentView;
+
+- (id)initWithSize:(CGSize)theSize
+ anchorRect:(CGRect)anchorRect
+ displayArea:(CGRect)displayArea
+permittedArrowDirections:(UIPopoverArrowDirection)permittedArrowDirections
+ properties:(WEPopoverContainerViewProperties *)theProperties {
+ if ((self = [super initWithFrame:CGRectZero])) {
+
+ [self setProperties:theProperties];
+ correctedSize = CGSizeMake(theSize.width + properties.leftBgMargin + properties.rightBgMargin + properties.leftContentMargin + properties.rightContentMargin,
+ theSize.height + properties.topBgMargin + properties.bottomBgMargin + properties.topContentMargin + properties.bottomContentMargin);
+ [self determineGeometryForSize:correctedSize anchorRect:anchorRect displayArea:displayArea permittedArrowDirections:permittedArrowDirections];
+ [self initFrame];
+ self.backgroundColor = [UIColor clearColor];
+ UIImage *theImage = [UIImage imageNamed:properties.bgImageName];
+ bgImage = [theImage stretchableImageWithLeftCapWidth:properties.leftBgCapSize topCapHeight:properties.topBgCapSize];
+
+ self.clipsToBounds = YES;
+ self.userInteractionEnabled = YES;
+ }
+ return self;
+}
+
+//- (void)dealloc {
+// [properties release];
+// [contentView release];
+// [bgImage release];
+// [arrowImage release];
+// [super dealloc];
+//}
+
+- (void)drawRect:(CGRect)rect {
+ [bgImage drawInRect:bgRect blendMode:kCGBlendModeNormal alpha:1.0];
+ [arrowImage drawInRect:arrowRect blendMode:kCGBlendModeNormal alpha:1.0];
+}
+
+- (void)updatePositionWithSize:(CGSize)theSize
+ anchorRect:(CGRect)anchorRect
+ displayArea:(CGRect)displayArea
+ permittedArrowDirections:(UIPopoverArrowDirection)permittedArrowDirections {
+
+ correctedSize = CGSizeMake(theSize.width + properties.leftBgMargin + properties.rightBgMargin + properties.leftContentMargin + properties.rightContentMargin,
+ theSize.height + properties.topBgMargin + properties.bottomBgMargin + properties.topContentMargin + properties.bottomContentMargin);
+ [self determineGeometryForSize:correctedSize anchorRect:anchorRect displayArea:displayArea permittedArrowDirections:permittedArrowDirections];
+ [self initFrame];
+ [self setNeedsDisplay];
+
+}
+
+- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
+ return CGRectContainsPoint(self.contentRect, point);
+}
+
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
+
+}
+
+- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
+
+}
+
+- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
+
+}
+
+- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
+
+}
+
+- (void)setContentView:(UIView *)v {
+ if (v != contentView) {
+// [contentView release];
+ contentView = v;
+ contentView.frame = self.contentRect;
+ [self addSubview:contentView];
+ }
+}
+
+
+
+@end
+
+@implementation WEPopoverContainerView(Private)
+
+- (void)initFrame {
+ CGRect theFrame = CGRectOffset(CGRectUnion(bgRect, arrowRect), offset.x, offset.y);
+
+ //If arrow rect origin is < 0 the frame above is extended to include it so we should offset the other rects
+ arrowOffset = CGPointMake(MAX(0, -arrowRect.origin.x), MAX(0, -arrowRect.origin.y));
+ bgRect = CGRectOffset(bgRect, arrowOffset.x, arrowOffset.y);
+ arrowRect = CGRectOffset(arrowRect, arrowOffset.x, arrowOffset.y);
+
+ self.frame = CGRectIntegral(theFrame);
+}
+
+- (CGSize)contentSize {
+ return self.contentRect.size;
+}
+
+- (CGRect)contentRect {
+ CGRect rect = CGRectMake(properties.leftBgMargin + properties.leftContentMargin + arrowOffset.x,
+ properties.topBgMargin + properties.topContentMargin + arrowOffset.y,
+ bgRect.size.width - properties.leftBgMargin - properties.rightBgMargin - properties.leftContentMargin - properties.rightContentMargin,
+ bgRect.size.height - properties.topBgMargin - properties.bottomBgMargin - properties.topContentMargin - properties.bottomContentMargin);
+ return rect;
+}
+
+- (void)setProperties:(WEPopoverContainerViewProperties *)props {
+ if (properties != props) {
+// [properties release];
+ properties = props;
+ }
+}
+
+- (void)determineGeometryForSize:(CGSize)theSize anchorRect:(CGRect)anchorRect displayArea:(CGRect)displayArea permittedArrowDirections:(UIPopoverArrowDirection)supportedArrowDirections {
+
+ //Determine the frame, it should not go outside the display area
+ UIPopoverArrowDirection theArrowDirection = UIPopoverArrowDirectionUp;
+
+ offset = CGPointZero;
+ bgRect = CGRectZero;
+ arrowRect = CGRectZero;
+ arrowDirection = UIPopoverArrowDirectionUnknown;
+
+ CGFloat biggestSurface = 0.0f;
+ CGFloat currentMinMargin = 0.0f;
+
+ UIImage *upArrowImage = [UIImage imageNamed:properties.upArrowImageName];
+ UIImage *downArrowImage = [UIImage imageNamed:properties.downArrowImageName];
+ UIImage *leftArrowImage = [UIImage imageNamed:properties.leftArrowImageName];
+ UIImage *rightArrowImage = [UIImage imageNamed:properties.rightArrowImageName];
+
+ while (theArrowDirection <= UIPopoverArrowDirectionRight) {
+
+ if ((supportedArrowDirections & theArrowDirection)) {
+
+ CGRect theBgRect = CGRectMake(0, 0, theSize.width, theSize.height);
+ CGRect theArrowRect = CGRectZero;
+ CGPoint theOffset = CGPointZero;
+ CGFloat xArrowOffset = 0.0;
+ CGFloat yArrowOffset = 0.0;
+ CGPoint anchorPoint = CGPointZero;
+
+ switch (theArrowDirection) {
+ case UIPopoverArrowDirectionUp:
+
+ anchorPoint = CGPointMake(CGRectGetMidX(anchorRect) - displayArea.origin.x, CGRectGetMaxY(anchorRect) - displayArea.origin.y);
+
+ xArrowOffset = theSize.width / 2 - upArrowImage.size.width / 2;
+ yArrowOffset = properties.topBgMargin - upArrowImage.size.height;
+
+ theOffset = CGPointMake(anchorPoint.x - xArrowOffset - upArrowImage.size.width / 2, anchorPoint.y - yArrowOffset);
+
+ if (theOffset.x < 0) {
+ xArrowOffset += theOffset.x;
+ theOffset.x = 0;
+ } else if (theOffset.x + theSize.width > displayArea.size.width) {
+ xArrowOffset += (theOffset.x + theSize.width - displayArea.size.width);
+ theOffset.x = displayArea.size.width - theSize.width;
+ }
+
+ //Cap the arrow offset
+ xArrowOffset = MAX(xArrowOffset, properties.leftBgMargin + properties.arrowMargin);
+ xArrowOffset = MIN(xArrowOffset, theSize.width - properties.rightBgMargin - properties.arrowMargin - upArrowImage.size.width);
+
+ theArrowRect = CGRectMake(xArrowOffset, yArrowOffset, upArrowImage.size.width, upArrowImage.size.height);
+
+ break;
+ case UIPopoverArrowDirectionDown:
+
+ anchorPoint = CGPointMake(CGRectGetMidX(anchorRect) - displayArea.origin.x, CGRectGetMinY(anchorRect) - displayArea.origin.y);
+
+ xArrowOffset = theSize.width / 2 - downArrowImage.size.width / 2;
+ yArrowOffset = theSize.height - properties.bottomBgMargin;
+
+ theOffset = CGPointMake(anchorPoint.x - xArrowOffset - downArrowImage.size.width / 2, anchorPoint.y - yArrowOffset - downArrowImage.size.height);
+
+ if (theOffset.x < 0) {
+ xArrowOffset += theOffset.x;
+ theOffset.x = 0;
+ } else if (theOffset.x + theSize.width > displayArea.size.width) {
+ xArrowOffset += (theOffset.x + theSize.width - displayArea.size.width);
+ theOffset.x = displayArea.size.width - theSize.width;
+ }
+
+ //Cap the arrow offset
+ xArrowOffset = MAX(xArrowOffset, properties.leftBgMargin + properties.arrowMargin);
+ xArrowOffset = MIN(xArrowOffset, theSize.width - properties.rightBgMargin - properties.arrowMargin - downArrowImage.size.width);
+
+ theArrowRect = CGRectMake(xArrowOffset , yArrowOffset, downArrowImage.size.width, downArrowImage.size.height);
+
+ break;
+ case UIPopoverArrowDirectionLeft:
+
+ anchorPoint = CGPointMake(CGRectGetMaxX(anchorRect) - displayArea.origin.x, CGRectGetMidY(anchorRect) - displayArea.origin.y);
+
+ xArrowOffset = properties.leftBgMargin - leftArrowImage.size.width;
+ yArrowOffset = theSize.height / 2 - leftArrowImage.size.height / 2;
+
+ theOffset = CGPointMake(anchorPoint.x - xArrowOffset, anchorPoint.y - yArrowOffset - leftArrowImage.size.height / 2);
+
+ if (theOffset.y < 0) {
+ yArrowOffset += theOffset.y;
+ theOffset.y = 0;
+ } else if (theOffset.y + theSize.height > displayArea.size.height) {
+ yArrowOffset += (theOffset.y + theSize.height - displayArea.size.height);
+ theOffset.y = displayArea.size.height - theSize.height;
+ }
+
+ //Cap the arrow offset
+ yArrowOffset = MAX(yArrowOffset, properties.topBgMargin + properties.arrowMargin);
+ yArrowOffset = MIN(yArrowOffset, theSize.height - properties.bottomBgMargin - properties.arrowMargin - leftArrowImage.size.height);
+
+ theArrowRect = CGRectMake(xArrowOffset, yArrowOffset, leftArrowImage.size.width, leftArrowImage.size.height);
+
+ break;
+ case UIPopoverArrowDirectionRight:
+
+ anchorPoint = CGPointMake(CGRectGetMinX(anchorRect) - displayArea.origin.x, CGRectGetMidY(anchorRect) - displayArea.origin.y);
+
+ xArrowOffset = theSize.width - properties.rightBgMargin;
+ yArrowOffset = theSize.height / 2 - rightArrowImage.size.width / 2;
+
+ theOffset = CGPointMake(anchorPoint.x - xArrowOffset - rightArrowImage.size.width, anchorPoint.y - yArrowOffset - rightArrowImage.size.height / 2);
+
+ if (theOffset.y < 0) {
+ yArrowOffset += theOffset.y;
+ theOffset.y = 0;
+ } else if (theOffset.y + theSize.height > displayArea.size.height) {
+ yArrowOffset += (theOffset.y + theSize.height - displayArea.size.height);
+ theOffset.y = displayArea.size.height - theSize.height;
+ }
+
+ //Cap the arrow offset
+ yArrowOffset = MAX(yArrowOffset, properties.topBgMargin + properties.arrowMargin);
+ yArrowOffset = MIN(yArrowOffset, theSize.height - properties.bottomBgMargin - properties.arrowMargin - rightArrowImage.size.height);
+
+ theArrowRect = CGRectMake(xArrowOffset, yArrowOffset, rightArrowImage.size.width, rightArrowImage.size.height);
+
+ break;
+ default:
+ break;
+ }
+
+ CGRect bgFrame = CGRectOffset(theBgRect, theOffset.x, theOffset.y);
+
+ CGFloat minMarginLeft = CGRectGetMinX(bgFrame);
+ CGFloat minMarginRight = CGRectGetWidth(displayArea) - CGRectGetMaxX(bgFrame);
+ CGFloat minMarginTop = CGRectGetMinY(bgFrame);
+ CGFloat minMarginBottom = CGRectGetHeight(displayArea) - CGRectGetMaxY(bgFrame);
+
+ if (minMarginLeft < 0) {
+ // Popover is too wide and clipped on the left; decrease width
+ // and move it to the right
+ theOffset.x -= minMarginLeft;
+ theBgRect.size.width += minMarginLeft;
+ minMarginLeft = 0;
+ if (theArrowDirection == UIPopoverArrowDirectionRight) {
+ theArrowRect.origin.x = CGRectGetMaxX(theBgRect) - properties.rightBgMargin;
+ }
+ }
+ if (minMarginRight < 0) {
+ // Popover is too wide and clipped on the right; decrease width.
+ theBgRect.size.width += minMarginRight;
+ minMarginRight = 0;
+ if (theArrowDirection == UIPopoverArrowDirectionLeft) {
+ theArrowRect.origin.x = CGRectGetMinX(theBgRect) - leftArrowImage.size.width + properties.leftBgMargin;
+ }
+ }
+ if (minMarginTop < 0) {
+ // Popover is too high and clipped at the top; decrease height
+ // and move it down
+ theOffset.y -= minMarginTop;
+ theBgRect.size.height += minMarginTop;
+ minMarginTop = 0;
+ if (theArrowDirection == UIPopoverArrowDirectionDown) {
+ theArrowRect.origin.y = CGRectGetMaxY(theBgRect) - properties.bottomBgMargin;
+ }
+ }
+ if (minMarginBottom < 0) {
+ // Popover is too high and clipped at the bottom; decrease height.
+ theBgRect.size.height += minMarginBottom;
+ minMarginBottom = 0;
+ if (theArrowDirection == UIPopoverArrowDirectionUp) {
+ theArrowRect.origin.y = CGRectGetMinY(theBgRect) - upArrowImage.size.height + properties.topBgMargin;
+ }
+ }
+ bgFrame = CGRectOffset(theBgRect, theOffset.x, theOffset.y);
+
+ CGFloat minMargin = MIN(minMarginLeft, minMarginRight);
+ minMargin = MIN(minMargin, minMarginTop);
+ minMargin = MIN(minMargin, minMarginBottom);
+
+ // Calculate intersection and surface
+ CGFloat surface = theBgRect.size.width * theBgRect.size.height;
+
+ if (surface >= biggestSurface && minMargin >= currentMinMargin) {
+ biggestSurface = surface;
+ offset = CGPointMake(theOffset.x + displayArea.origin.x, theOffset.y + displayArea.origin.y);
+ arrowRect = theArrowRect;
+ bgRect = theBgRect;
+ arrowDirection = theArrowDirection;
+ currentMinMargin = minMargin;
+ }
+ }
+
+ theArrowDirection <<= 1;
+ }
+
+ switch (arrowDirection) {
+ case UIPopoverArrowDirectionUp:
+ arrowImage = upArrowImage;
+ break;
+ case UIPopoverArrowDirectionDown:
+ arrowImage = downArrowImage;
+ break;
+ case UIPopoverArrowDirectionLeft:
+ arrowImage = leftArrowImage;
+ break;
+ case UIPopoverArrowDirectionRight:
+ arrowImage = rightArrowImage;
+ break;
+ default:
+ break;
+ }
+}
+
+@end
diff --git a/QRichTextView/Classes/WEPopoverController.h b/QRichTextView/Classes/WEPopoverController.h
new file mode 100755
index 0000000..068a799
--- /dev/null
+++ b/QRichTextView/Classes/WEPopoverController.h
@@ -0,0 +1,75 @@
+//
+// WEPopoverController.h
+// WEPopover
+//
+// Created by Werner Altewischer on 02/09/10.
+// Copyright 2010 Werner IT Consultancy. All rights reserved.
+//
+
+#import
+#import
+#import "WEPopoverContainerView.h"
+#import "WETouchableView.h"
+
+@class WEPopoverController;
+
+@protocol WEPopoverControllerDelegate
+
+- (void)popoverControllerDidDismissPopover:(WEPopoverController *)popoverController;
+- (BOOL)popoverControllerShouldDismissPopover:(WEPopoverController *)popoverController;
+
+@end
+
+/**
+ * @brief Popover controller for the iPhone, mimicing the iPad UIPopoverController interface. See that class for more details.
+ */
+@interface WEPopoverController : NSObject {
+ UIViewController *contentViewController;
+ UIView *view;
+// UIView *parentView;
+ WETouchableView *backgroundView;
+
+ BOOL popoverVisible;
+ UIPopoverArrowDirection popoverArrowDirection;
+// id delegate;
+ CGSize popoverContentSize;
+ WEPopoverContainerViewProperties *containerViewProperties;
+ id context;
+ NSArray *passthroughViews;
+}
+
+@property(nonatomic, retain) UIViewController *contentViewController;
+
+@property (nonatomic, readonly) UIView *view;
+@property (nonatomic, readonly, getter=isPopoverVisible) BOOL popoverVisible;
+@property (nonatomic, readonly) UIPopoverArrowDirection popoverArrowDirection;
+@property (nonatomic, weak) id delegate;
+@property (nonatomic, assign) CGSize popoverContentSize;
+@property (nonatomic, retain) WEPopoverContainerViewProperties *containerViewProperties;
+@property (nonatomic, retain) id context;
+@property (nonatomic, weak) UIView *parentView;
+@property (nonatomic, copy) NSArray *passthroughViews;
+
+- (id)initWithContentViewController:(UIViewController *)theContentViewController;
+
+- (void)dismissPopoverAnimated:(BOOL)animated;
+
+- (void)presentPopoverFromBarButtonItem:(UIBarButtonItem *)item
+ permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections
+ animated:(BOOL)animated;
+
+- (void)presentPopoverFromRect:(CGRect)rect
+ inView:(UIView *)view
+ permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections
+ animated:(BOOL)animated;
+
+- (void)repositionPopoverFromRect:(CGRect)rect
+ inView:(UIView *)view
+ permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections;
+
+- (void)repositionPopoverFromRect:(CGRect)rect
+ inView:(UIView *)view
+ permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections
+ animated:(BOOL)animated;
+
+@end
diff --git a/QRichTextView/Classes/WEPopoverController.m b/QRichTextView/Classes/WEPopoverController.m
new file mode 100755
index 0000000..2ef2b8e
--- /dev/null
+++ b/QRichTextView/Classes/WEPopoverController.m
@@ -0,0 +1,377 @@
+//
+// WEPopoverController.m
+// WEPopover
+//
+// Created by Werner Altewischer on 02/09/10.
+// Copyright 2010 Werner IT Consultancy. All rights reserved.
+//
+
+#import "WEPopoverController.h"
+#import "WEPopoverParentView.h"
+#import "UIBarButtonItem+WEPopover.h"
+
+#define FADE_DURATION 0.3
+
+@interface WEPopoverController(Private)
+
+- (UIView *)keyView;
+- (void)updateBackgroundPassthroughViews;
+- (void)setView:(UIView *)v;
+- (CGRect)displayAreaForView:(UIView *)theView;
+- (WEPopoverContainerViewProperties *)defaultContainerViewProperties;
+- (void)dismissPopoverAnimated:(BOOL)animated userInitiated:(BOOL)userInitiated;
+
+@end
+
+
+@implementation WEPopoverController
+
+@synthesize contentViewController;
+@synthesize popoverContentSize;
+@synthesize popoverVisible;
+@synthesize popoverArrowDirection;
+@synthesize delegate;
+@synthesize view;
+@synthesize parentView;
+@synthesize containerViewProperties;
+@synthesize context;
+@synthesize passthroughViews;
+
+- (id)init {
+ if ((self = [super init])) {
+ }
+ return self;
+}
+
+- (id)initWithContentViewController:(UIViewController *)viewController {
+ if ((self = [self init])) {
+ self.contentViewController = viewController;
+ }
+ return self;
+}
+
+//- (void)dealloc {
+// [self dismissPopoverAnimated:NO];
+// [contentViewController release];
+// [containerViewProperties release];
+// [passthroughViews release];
+// self.context = nil;
+// [super dealloc];
+//}
+
+- (void)setContentViewController:(UIViewController *)vc {
+ if (vc != contentViewController) {
+// [contentViewController release];
+ contentViewController = vc;
+ popoverContentSize = CGSizeZero;
+ }
+}
+
+- (BOOL)forwardAppearanceMethods {
+ return ![contentViewController respondsToSelector:@selector(automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers)];
+}
+
+//Overridden setter to copy the passthroughViews to the background view if it exists already
+- (void)setPassthroughViews:(NSArray *)array {
+// [passthroughViews release];
+ passthroughViews = nil;
+ if (array) {
+ passthroughViews = [[NSArray alloc] initWithArray:array];
+ }
+ [self updateBackgroundPassthroughViews];
+}
+
+- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)theContext {
+
+ if ([animationID isEqual:@"FadeIn"]) {
+ self.view.userInteractionEnabled = YES;
+ popoverVisible = YES;
+
+ if ([self forwardAppearanceMethods]) {
+ [contentViewController viewDidAppear:YES];
+ }
+ } else if ([animationID isEqual:@"FadeOut"]) {
+ popoverVisible = NO;
+
+ if ([self forwardAppearanceMethods]) {
+ [contentViewController viewDidDisappear:YES];
+ }
+ [self.view removeFromSuperview];
+ self.view = nil;
+ [backgroundView removeFromSuperview];
+// [backgroundView release];
+ backgroundView = nil;
+
+ BOOL userInitiatedDismissal = [(__bridge NSNumber *)theContext boolValue];
+
+ if (userInitiatedDismissal) {
+ //Only send message to delegate in case the user initiated this event, which is if he touched outside the view
+ [delegate popoverControllerDidDismissPopover:self];
+ }
+ }
+}
+
+- (void)dismissPopoverAnimated:(BOOL)animated {
+
+ [self dismissPopoverAnimated:animated userInitiated:NO];
+}
+
+- (void)presentPopoverFromBarButtonItem:(UIBarButtonItem *)item
+ permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections
+ animated:(BOOL)animated {
+
+ UIView *v = [self keyView];
+ CGRect rect = [item frameInView:v];
+
+ return [self presentPopoverFromRect:rect inView:v permittedArrowDirections:arrowDirections animated:animated];
+}
+
+- (void)presentPopoverFromRect:(CGRect)rect
+ inView:(UIView *)theView
+ permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections
+ animated:(BOOL)animated {
+
+
+ [self dismissPopoverAnimated:NO];
+
+ //First force a load view for the contentViewController so the popoverContentSize is properly initialized
+ [contentViewController view];
+
+ if (CGSizeEqualToSize(popoverContentSize, CGSizeZero)) {
+ popoverContentSize = contentViewController.preferredContentSize;
+ }
+
+ CGRect displayArea = [self displayAreaForView:theView];
+
+ WEPopoverContainerViewProperties *props = self.containerViewProperties ? self.containerViewProperties : [self defaultContainerViewProperties];
+ WEPopoverContainerView *containerView = [[WEPopoverContainerView alloc] initWithSize:self.popoverContentSize anchorRect:rect displayArea:displayArea permittedArrowDirections:arrowDirections properties:props];
+ popoverArrowDirection = containerView.arrowDirection;
+
+ UIView *keyView = self.keyView;
+
+ backgroundView = [[WETouchableView alloc] initWithFrame:keyView.bounds];
+ backgroundView.contentMode = UIViewContentModeScaleToFill;
+ backgroundView.autoresizingMask = ( UIViewAutoresizingFlexibleLeftMargin |
+ UIViewAutoresizingFlexibleWidth |
+ UIViewAutoresizingFlexibleRightMargin |
+ UIViewAutoresizingFlexibleTopMargin |
+ UIViewAutoresizingFlexibleHeight |
+ UIViewAutoresizingFlexibleBottomMargin);
+ backgroundView.backgroundColor = [UIColor clearColor];
+ backgroundView.delegate = self;
+
+ [keyView addSubview:backgroundView];
+
+ containerView.frame = [theView convertRect:containerView.frame toView:backgroundView];
+
+ [backgroundView addSubview:containerView];
+
+ containerView.contentView = contentViewController.view;
+ containerView.autoresizingMask = ( UIViewAutoresizingFlexibleLeftMargin |
+ UIViewAutoresizingFlexibleRightMargin);
+
+ self.view = containerView;
+ [self updateBackgroundPassthroughViews];
+
+ if ([self forwardAppearanceMethods]) {
+ [contentViewController viewWillAppear:animated];
+ }
+ [self.view becomeFirstResponder];
+ popoverVisible = YES;
+ if (animated) {
+ self.view.alpha = 0.0;
+
+ [UIView animateWithDuration:FADE_DURATION
+ delay:0.0
+ options:UIViewAnimationOptionCurveLinear
+ animations:^{
+
+ self.view.alpha = 1.0;
+
+ } completion:^(BOOL finished) {
+
+ [self animationDidStop:@"FadeIn" finished:[NSNumber numberWithBool:finished] context:nil];
+ }];
+
+ } else {
+ if ([self forwardAppearanceMethods]) {
+ [contentViewController viewDidAppear:animated];
+ }
+ }
+}
+
+- (void)repositionPopoverFromRect:(CGRect)rect
+ inView:(UIView *)theView
+ permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections
+{
+
+ [self repositionPopoverFromRect:rect
+ inView:theView
+ permittedArrowDirections:arrowDirections
+ animated:NO];
+}
+
+- (void)repositionPopoverFromRect:(CGRect)rect
+ inView:(UIView *)theView
+ permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections
+ animated:(BOOL)animated {
+
+ if (animated) {
+ [UIView beginAnimations:nil context:nil];
+ [UIView setAnimationDuration:FADE_DURATION];
+ [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
+// [UIView animateWithDuration:FADE_DURATION delay:0 options:UIViewAnimationOptionCurveEaseOut animations:nil completion:nil];
+ }
+
+ if (CGSizeEqualToSize(popoverContentSize, CGSizeZero)) {
+ popoverContentSize = contentViewController.preferredContentSize;
+ }
+
+ CGRect displayArea = [self displayAreaForView:theView];
+ WEPopoverContainerView *containerView = (WEPopoverContainerView *)self.view;
+ [containerView updatePositionWithSize:self.popoverContentSize
+ anchorRect:rect
+ displayArea:displayArea
+ permittedArrowDirections:arrowDirections];
+
+ popoverArrowDirection = containerView.arrowDirection;
+ containerView.frame = [theView convertRect:containerView.frame toView:backgroundView];
+
+ if (animated) {
+ [UIView commitAnimations];
+ }
+}
+
+#pragma mark -
+#pragma mark WETouchableViewDelegate implementation
+
+- (void)viewWasTouched:(WETouchableView *)view {
+ if (popoverVisible) {
+ if (!delegate || [delegate popoverControllerShouldDismissPopover:self]) {
+ [self dismissPopoverAnimated:YES userInitiated:YES];
+ }
+ }
+}
+
+- (BOOL)isPopoverVisible {
+ if (!popoverVisible) {
+ return NO;
+ }
+ UIView *sv = self.view;
+ BOOL foundWindowAsSuperView = NO;
+ while ((sv = sv.superview) != nil) {
+ if ([sv isKindOfClass:[UIWindow class]]) {
+ foundWindowAsSuperView = YES;
+ break;
+ }
+ }
+ return foundWindowAsSuperView;
+}
+
+@end
+
+
+@implementation WEPopoverController(Private)
+
+- (UIView *)keyView {
+ if (self.parentView) {
+ return self.parentView;
+ } else {
+ UIWindow *w = [[UIApplication sharedApplication] keyWindow];
+ if (w.subviews.count > 0) {
+ return [w.subviews objectAtIndex:0];
+ } else {
+ return w;
+ }
+ }
+}
+
+- (void)setView:(UIView *)v {
+ if (view != v) {
+// [view release];
+ view = v;
+ }
+}
+
+- (void)updateBackgroundPassthroughViews {
+ backgroundView.passthroughViews = passthroughViews;
+}
+
+
+- (void)dismissPopoverAnimated:(BOOL)animated userInitiated:(BOOL)userInitiated {
+ if (self.view) {
+ if ([self forwardAppearanceMethods]) {
+ [contentViewController viewWillDisappear:animated];
+ }
+ popoverVisible = NO;
+ [self.view resignFirstResponder];
+ if (animated) {
+ self.view.userInteractionEnabled = NO;
+
+ [UIView animateWithDuration:FADE_DURATION
+ delay:0.0
+ options:UIViewAnimationOptionCurveLinear
+ animations:^{
+
+ self.view.alpha = 0.0;
+
+ } completion:^(BOOL finished) {
+
+ [self animationDidStop:@"FadeOut" finished:[NSNumber numberWithBool:finished] context:(__bridge void *)([NSNumber numberWithBool:userInitiated])];
+ }];
+
+
+ } else {
+ if ([self forwardAppearanceMethods]) {
+ [contentViewController viewDidDisappear:animated];
+ }
+ [self.view removeFromSuperview];
+ self.view = nil;
+ [backgroundView removeFromSuperview];
+// [backgroundView release];
+ backgroundView = nil;
+ }
+ }
+}
+
+- (CGRect)displayAreaForView:(UIView *)theView {
+ CGRect displayArea = CGRectZero;
+ if ([theView conformsToProtocol:@protocol(WEPopoverParentView)] && [theView respondsToSelector:@selector(displayAreaForPopover)]) {
+ displayArea = [(id )theView displayAreaForPopover];
+ } else {
+ UIView *keyView = [self keyView];
+ displayArea = [keyView convertRect:keyView.bounds toView:theView];
+ }
+ return displayArea;
+}
+
+//Enable to use the simple popover style
+- (WEPopoverContainerViewProperties *)defaultContainerViewProperties {
+ WEPopoverContainerViewProperties *ret = [WEPopoverContainerViewProperties new];
+
+ CGSize imageSize = CGSizeMake(30.0f, 30.0f);
+ NSString *bgImageName = @"popoverBgSimple.png";
+ CGFloat bgMargin = 6.0;
+ CGFloat contentMargin = 2.0;
+
+ ret.leftBgMargin = bgMargin;
+ ret.rightBgMargin = bgMargin;
+ ret.topBgMargin = bgMargin;
+ ret.bottomBgMargin = bgMargin;
+ ret.leftBgCapSize = imageSize.width/2;
+ ret.topBgCapSize = imageSize.height/2;
+ ret.bgImageName = bgImageName;
+ ret.leftContentMargin = contentMargin;
+ ret.rightContentMargin = contentMargin;
+ ret.topContentMargin = contentMargin;
+ ret.bottomContentMargin = contentMargin;
+ ret.arrowMargin = 1.0;
+
+ ret.upArrowImageName = @"popoverArrowUpSimple.png";
+ ret.downArrowImageName = @"popoverArrowDownSimple.png";
+ ret.leftArrowImageName = @"popoverArrowLeftSimple.png";
+ ret.rightArrowImageName = @"popoverArrowRightSimple.png";
+ return ret;
+}
+
+@end
diff --git a/QRichTextView/Classes/WEPopoverParentView.h b/QRichTextView/Classes/WEPopoverParentView.h
new file mode 100755
index 0000000..d881bfe
--- /dev/null
+++ b/QRichTextView/Classes/WEPopoverParentView.h
@@ -0,0 +1,18 @@
+/*
+ * WEPopoverParentView.h
+ * WEPopover
+ *
+ * Created by Werner Altewischer on 02/09/10.
+ * Copyright 2010 Werner IT Consultancy. All rights reserved.
+ *
+ */
+
+#import
+#import
+
+@protocol WEPopoverParentView
+
+@optional
+- (CGRect)displayAreaForPopover;
+
+@end
\ No newline at end of file
diff --git a/QRichTextView/Classes/WETouchableView.h b/QRichTextView/Classes/WETouchableView.h
new file mode 100755
index 0000000..39432b9
--- /dev/null
+++ b/QRichTextView/Classes/WETouchableView.h
@@ -0,0 +1,37 @@
+//
+// WETouchableView.h
+// WEPopover
+//
+// Created by Werner Altewischer on 12/21/10.
+// Copyright 2010 Werner IT Consultancy. All rights reserved.
+//
+
+#import
+#import
+
+@class WETouchableView;
+
+/**
+ * @brief delegate to receive touch events
+ */
+@protocol WETouchableViewDelegate
+
+- (void)viewWasTouched:(WETouchableView *)view;
+
+@end
+
+/**
+ * @brief View that can handle touch events and/or disable touch forwording to child views
+ */
+@interface WETouchableView : UIView {
+ BOOL touchForwardingDisabled;
+// id delegate;
+ NSArray *passthroughViews;
+ BOOL testHits;
+}
+
+@property (nonatomic, assign) BOOL touchForwardingDisabled;
+@property (nonatomic, weak) id delegate;
+@property (nonatomic, copy) NSArray *passthroughViews;
+
+@end
diff --git a/QRichTextView/Classes/WETouchableView.m b/QRichTextView/Classes/WETouchableView.m
new file mode 100755
index 0000000..2a0d49e
--- /dev/null
+++ b/QRichTextView/Classes/WETouchableView.m
@@ -0,0 +1,70 @@
+//
+// WETouchableView.m
+// WEPopover
+//
+// Created by Werner Altewischer on 12/21/10.
+// Copyright 2010 Werner IT Consultancy. All rights reserved.
+//
+
+#import "WETouchableView.h"
+
+@interface WETouchableView(Private)
+
+- (BOOL)isPassthroughView:(UIView *)v;
+
+@end
+
+@implementation WETouchableView
+
+@synthesize touchForwardingDisabled, delegate, passthroughViews;
+
+//- (void)dealloc {
+// [passthroughViews release];
+// [super dealloc];
+//}
+
+- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
+ if (testHits) {
+ return nil;
+ } else if (touchForwardingDisabled) {
+ return self;
+ } else {
+ UIView *hitView = [super hitTest:point withEvent:event];
+
+ if (hitView == self) {
+ //Test whether any of the passthrough views would handle this touch
+ testHits = YES;
+ UIView *superHitView = [self.superview hitTest:point withEvent:event];
+ testHits = NO;
+
+ if ([self isPassthroughView:superHitView]) {
+ hitView = superHitView;
+ }
+ }
+
+ return hitView;
+ }
+}
+
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
+ [self.delegate viewWasTouched:self];
+}
+
+@end
+
+@implementation WETouchableView(Private)
+
+- (BOOL)isPassthroughView:(UIView *)v {
+
+ if (v == nil) {
+ return NO;
+ }
+
+ if ([passthroughViews containsObject:v]) {
+ return YES;
+ }
+
+ return [self isPassthroughView:v.superview];
+}
+
+@end