I have a problem to make the keyDown: method run for each item in an NSCollectionView when I press a key from the keyboard.
Edit: I have the next code in my NSCollectionViewItem but does't work, how can I do that specially make work the acceptsFirstResponder:
- (BOOL)acceptsFirstResponder
{
[[[self view] window] makeFirstResponder:self];
return YES;
}
- (void)keyDown:(NSEvent*)event
{
NSString *chars = [event characters];
unichar character = [chars characterAtIndex: 0];
if(!sound){
sound = [[NSSound alloc] initWithContentsOfFile:textFile.stringValue byReference:YES];
}
if ([checkButton state]==1) {
[sound setLoops:YES];
}else{
[sound setLoops:NO];
}
if(character == (int)'w'){
if ([sound isPlaying]){
[sound stop];
[sound release];
sound = nil;
} else {
[sound play];
}
}
}
(Sorry for make a lot of changes is first question here)
Related
In building a custom NSButton, I've run into a problem handling highlight behavior. After clicking down on the button, holding, and dragging the cursor outside the button's bounds, mouseExited: and mouseEntered: events are not delivered. I understand the reason why, because in mouseDown: calling [super mouseDown:event]; will block until the click is released.
In researching this I came across this Stack Overflow post which describes the same problem. The solution noted is to add NSTrackingEnabledDuringMouseDrag to the NSTrackingArea options, which I have done, yet I continue to see this problem. I tried the other proposed solution with handling the next events in a loop, but this resulted in odd behavior. The button text color turns black on mouse down instead of highlighting the dimmed color, and it doesn't unhighlight upon releasing the mouse, it remains black.
I am using Xcode 9.3, running on macOS 10.13.4.
Here is my NSButton subclass:
#interface BorderlessButton : NSButton {
NSColor *_tempColor;
}
#property (strong, nonatomic) NSColor *color;
#end
#interface BorderlessButton ()
#property (nonatomic) BOOL pressed;
#end
#implementation BorderlessButton
- (id)init {
if (self = [super init]) {
[self setUp];
}
return self;
}
- (id)initWithFrame:(NSRect)frameRect {
if (self = [super initWithFrame:frameRect]) {
[self setUp];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
[self setUp];
}
return self;
}
- (void)setUp {
_color = [NSColor redColor];
[self setTitle:self.title];
[self setButtonType:NSButtonTypeMomentaryChange];
[self setBordered:NO];
NSTrackingArea *area = [[NSTrackingArea alloc] initWithRect:self.bounds
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingEnabledDuringMouseDrag
owner:self
userInfo:nil];
[self addTrackingArea:area];
}
- (void)setTitle:(NSString *)title {
[super setTitle:title];
NSMutableAttributedString *colorTitle = [[NSMutableAttributedString alloc] initWithAttributedString:[self attributedTitle]];
[colorTitle addAttributes:#{NSFontAttributeName: self.font, NSForegroundColorAttributeName: self.color} range:NSMakeRange(0, [colorTitle length])];
[self setAttributedTitle:colorTitle];
}
- (void)setColor:(NSColor *)color {
_color = color;
[self setTitle:self.title];
}
- (void)mouseDown:(NSEvent *)event {
self.pressed = YES;
[self highlight:YES];
[super mouseDown:event]; // this blocks until released
[self mouseUp:event];
}
- (void)mouseUp:(NSEvent *)event {
self.pressed = NO;
[self highlight:NO];
[super mouseUp:event];
}
//FIXME: Not called after mouse press down and hold then exit
- (void)mouseExited:(NSEvent *)event {
if (self.pressed) {
[self highlight:NO];
}
[super mouseExited:event];
}
- (void)mouseEntered:(NSEvent *)event {
if (self.pressed) {
[self highlight:YES];
}
[super mouseEntered:event];
}
- (void)highlight:(BOOL)flag {
if (flag) {
if (self.isEnabled) {
NSColor *dimmedColor = [self dimmedColor];
_tempColor = _color;
self.color = dimmedColor;
[self setTitle:self.title];
}
} else {
if (self.isEnabled) {
self.color = _tempColor;
[self setTitle:self.title];
}
}
}
- (NSColor *)dimmedColor {
return [self.color colorWithAlphaComponent:0.5];
}
#end
In Mavericks, the methods to open and close NSSheets has changed. And to make it tougher, the Release Notes do not match the current documentation (see below).
I'm trying to do this:
MainSheetController (NSWindowController):
-(IBAction)callSheet:(id)sender {
[sheetController openSheet];
}
SheetController (NSObject):
(void)openSheet {
[[NSBundle mainBundle] loadNibNamed:sheetName owner:self topLevelObjects:nil];
NSLog(#"1");
[self.mainWindowController.window beginSheet:self.sheet completionHandler:nil];
NSLog(#"2");
}
I get to 2, with no errors or warnings, but no sheet..
Current Documentation:
#if NS_BLOCKS_AVAILABLE
- (void)beginSheet:(NSWindow *)sheetWindow completionHandler:(void (^)(NSModalResponse returnCode))handler NS_AVAILABLE_MAC(10_9);
- (void)beginCriticalSheet:(NSWindow *)sheetWindow completionHandler:(void (^)(NSModalResponse returnCode))handler NS_AVAILABLE_MAC(10_9);
#endif
- (IBAction)userButtonPressed:(id)sender {
UserLoginWindowController * wc = [UserLoginWindowController new];
// we keep a reference, so the WC doesn't deallocate
self.modalWindowController = wc;
[[self window] beginSheet:[wc window] completionHandler:^(NSModalResponse returnCode) {
self.modalWindowController = nil;
}];
}
in the UserLoginWindowController
- (IBAction)cancelButtonPressed:(id)sender {
[[[self window] sheetParent] endSheet:[self window] returnCode:NSModalResponseCancel];
}
- (IBAction)showSheet:(id)sender
{
if (_windowController == nil)
{
_windowController = [MyWindowController new];
}
[[self window] beginSheet:[_windowController window] completionHandler:^(NSModalResponse returnCode)
{
}];
}
// And inside your MyWindowController class:
- (id)init
{
self = [super initWithWindowNibName:#"MyWindowNibName"]; // TODO: Change the name of your NIB
return self;
}
In your nib file, make sure the "Visible At Launch" flag is unticked for the window.
I figured out how to do this. Hope it's ok to post..
MainWindow.h
#interface MainWindowController : NSWindowController {
NSString *sheetName;
IBOutlet NSWindow *sheet;
id result1;
id result2;
...
id resultn;
}
#property (strong) NSString *sheetName;
#property (strong, nonatomic) IBOutlet NSWindow *sheet;
-(IBAction)callSheet0:(id)sender;
-(IBAction)callSheet1:(id)sender;
-(IBAction)callSheetn:(id)sender;
- (void)openSheet;
- (IBAction)save:(id)sender;
- (IBAction)cancel:(id)sender;
MainWindow.m
- (void)windowDidLoad
{
NSLog(#"%s", __FUNCTION__);
[super windowDidLoad];
sheetName = [[NSString alloc] init];
}
-(IBAction)callSheet0:(id)sender {
NSLog(#"%s", __FUNCTION__);
sheetName = #"Sheet0";
[self openSheet];
}
....
-(IBAction)callSheetn:(id)sender {
NSLog(#"%s", __FUNCTION__);
sheetName = #"Sheetn";
[self openSheet];
- (void)openSheet {
NSLog(#"%s", __FUNCTION__);
NSLog(#"sheetName: %#",sheetName );
[[NSBundle mainBundle] loadNibNamed:sheetName owner:self topLevelObjects:nil];
[self.window beginSheet:self.sheet completionHandler:nil];
}
- (void)save:(NSButton*)sender {
switch ([sender tag]) {
case 0:
[self doSave1];
result = #"1";
break;
case 1:
[self doSave2];
result = #"2";
break;
case n:
[self doSaven];
result = #"x";
break;
}
[self endSheet:self.sheet returnCode:result];
}
- (IBAction)cancel:(id)sender {
NSLog(#"%s", __FUNCTION__);
result = #"0";
[self endSheet:self.sheet returnCode:result];
// returnCode is optional
}
//endSheet:(NSWindow *)sheetWindow {
- (void)endSheet:(NSWindow *)sheetWindow returnCode:returnCode {
//NSLog(#"%s", __FUNCTION__);
[sheetWindow orderOut:self];
}
- (void)save:(NSButton*)sender {
switch ([sender tag]) {
case 0:
[self doSave1];
result = #"1";
break;
case n:
[self doSave3];
result = #"3";
break;
}
[self endSheet:self.sheet returnCode:result];
}
With this method, new in 10.9,I don't need a special sheet controller, and control remains quote local.
I want to fire a query when a particular record gets selected in an NSTableView, not when the user just scrolls down or scrolls up by continuously pressing UP/DOWN button to reach to a record.
My current implementation is
if ([notification object] == myTableView)
{
if ([myTableView selectedRow] >= 0) {
myCont = [[MyController alloc] init];
if([[detailsView subviews]count]>0)
[detailsView removeAllSubviews];
NSRect frameRect = [[scDetailsViewController view] frame];
frameRect.size.height = [detailsView frame].size.height;
frameRect.size.width = [detailsView frame].size.width;
[[myCont view] setFrame:frameRect];
[detailsView addSubview:[myCont view]];
//Firing the Query
[myCont populateDetails :[[self myList] entityAt:[myTableView selectedRow]]];
}
}
But in this way the query gets fired even if a long UP/DOWN press is done which is not intended.
Is there any way to distinguish between a click and scroll(continuous press of UP/DOWN key) inside an NSTableView just like the Mail application.
Just wrote the below piece of code in the tableViewSelectionDidChange method and that almost works perfectly.
- (void)tableViewSelectionDidChange:(NSNotification *)notification
{
if ([notification object] == myTableView)
{
NSTimeInterval delayInterval = 0.0;
NSEvent *event = [NSApp currentEvent];
if(event != nil && [event type] == NSKeyDown && [event isARepeat])
{
NSLog(#"Long press of UP and DOWn arrow key.");
delayInterval = [NSEvent keyRepeatInterval] + 0.01;
}
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(myMethod) object:nil];
[self performSelector:#selector(myMethod) withObject:nil afterDelay:delayInterval];
}
else
{
if ([[detailsView subviews] count]>0)
{
[detailsView removeAllSubviews];
}
}
}
Also written the code to fire the query in another method myMethod which is being called above in performSelector.
-(void) myMethod
{
if ([scenarioTableView selectedRow] >= 0) {
NSLog(#"Normal selection on table view row.");
scDetailsViewController = [[ScenarioDetailsViewController alloc] init];
if([[detailsView subviews]count]>0)
[detailsView removeAllSubviews];
NSRect frameRect = [[scDetailsViewController view] frame];
frameRect.size.height = [detailsView frame].size.height;
frameRect.size.width = [detailsView frame].size.width;
[[scDetailsViewController view] setFrame:frameRect];
[detailsView addSubview:[scDetailsViewController view]];
[scDetailsViewController populateScenarioDetails :[[self scenarioDetailsList] entityAt:[scenarioTableView selectedRow]]];
}
else {
if ([[detailsView subviews] count]>0)
{
[detailsView removeAllSubviews];
}
}
}
Modify your key event code something like this below and let me know if still you face any issue:-
NSInteger keyPress = [[NSApp currentEvent] type];
if (keyPress!=10)
{
}
NSLog(#"mouseclick");
}
else{
NSLog(#"keyboardClick");
}
When a new item is created in the NSOutlineView, I would like to have the item selected and editable, I'm currently using the following code within my NSOutlineview delegate/datasource, the new item is created, however it isn't focused/ editable.
NSWindow *w = [[self outlineView] window];
BOOL endEdit = [w makeFirstResponder:w];
if (!endEdit) {
return;
}
NSUInteger row = [[self outlineView] rowForItem:newGoal];
[[self outlineView] scrollRowToVisible:row];
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:row];
[[self outlineView] selectRowIndexes:indexSet byExtendingSelection:NO];
[[self outlineView] editColumn:0
row:row
withEvent:nil
select:YES];
NSError *anyError = nil;
BOOL success = [[self myContext] save:&anyError];
if (!success) {
NSLog(#"Error = %#", anyError);
}
My complete file is
//
// SBOutlineViewController.m
// Allocator
//
// Created by Cory Sullivan on 2013-04-21.
//
//
#import "SBOutlineViewController.h"
#import "SBAppDelegate.h"
#interface SBOutlineViewController ()
#end
NSString * const SBOutlineSelectionChangedNotification = #"SBSelectionChanged";
#implementation SBOutlineViewController
- (void)awakeFromNib
{
[self setTopLevelItems:[NSArray arrayWithObjects:#"Retirement", #"Education", nil]];
[self setMyContext:[[NSApp delegate] managedObjectContext]];
[self updateOutlineView];
}
- (void)updateOutlineView
{
NSFetchRequest *myRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *goalEntity = [NSEntityDescription entityForName:#"Goal" inManagedObjectContext:[self myContext]];
[myRequest setEntity:goalEntity];
NSError *anyError = nil;
[self setGoalItems:[[self myContext] executeFetchRequest:myRequest error:&anyError]];
NSMutableArray *retirementArray = [[NSMutableArray alloc] init];
NSMutableArray *educationArray = [[NSMutableArray alloc] init];
for (NSManagedObject *goalObject in [self goalItems]) {
if ([[goalObject valueForKey:#"goalType"] isEqual: #"Retirement"]) {
[retirementArray addObject:goalObject];
} else {
if ([[goalObject valueForKey:#"goalType"] isEqual:#"Education"]) {
[educationArray addObject:goalObject];
}
}
}
[self setMyOutlineDictionary:[[NSMutableDictionary alloc] initWithObjectsAndKeys:retirementArray, #"Retirement", educationArray, #"Education", nil]];
[[self outlineView] reloadData];
}
#pragma mark - Delegate and DataSoure Methods
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
return [[self _childrenForItem:item] objectAtIndex:index];
}
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
if ([outlineView parentForItem:item] == nil) {
return YES;
} else {
return NO;
}
}
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item
{
if ([outlineView parentForItem:item] == nil) {
return NO;
} else {
return YES;
}
}
- (NSInteger) outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
return [[self _childrenForItem:item] count];
}
- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item {
return [_topLevelItems containsObject:item];
}
- (void)outlineViewSelectionDidChange:(NSNotification *)notification {
if ([_outlineView selectedRow] != -1) {
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc postNotificationName:SBOutlineSelectionChangedNotification object:self];
}
}
- (NSArray *)_childrenForItem:(id)item {
NSArray *children;
if (item == nil) {
children = _topLevelItems;
} else {
children = [_myOutlineDictionary objectForKey:item];
}
return children;
}
- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
NSTableCellView *view = nil;
if ([_topLevelItems containsObject:item]) {
view = [outlineView makeViewWithIdentifier:#"HeaderCell" owner:self];
NSString *value = [item uppercaseString];
[[view textField] setStringValue:value];
return view;
} else {
view = [outlineView makeViewWithIdentifier:#"DataCell" owner:self];
[[view imageView] setImage:[NSImage imageNamed:NSImageNameActionTemplate]];
NSManagedObject *goalItem = [_goalItems objectAtIndex:[_goalItems indexOfObject:item]];
[[view textField] setStringValue:[goalItem valueForKey:#"goalName"]];
return view;
}
}
#pragma mark - Custom Actions
- (IBAction)goalActionPullDown:(id)sender
{
[self modifyGoalItems: [[sender selectedItem] tag]];
}
- (void)modifyGoalItems:(NSInteger)whichMenuTag
{
if (whichMenuTag == 5) {
NSAlert *alert = [NSAlert alertWithMessageText:#"Are you sure you want to delete goal and all related accounts?"
defaultButton:#"Remove"
alternateButton:#"Cancel"
otherButton:nil
informativeTextWithFormat:#"This can't be undone"];
[alert beginSheetModalForWindow:[_outlineView window]
modalDelegate:self
didEndSelector:#selector(alertEnded:code:context:)
contextInfo:NULL];
} else {
NSManagedObject *newGoal = [NSEntityDescription insertNewObjectForEntityForName:#"Goal" inManagedObjectContext:[self myContext]];
switch (whichMenuTag) {
case 1:
{
[newGoal setValue:#"New Goal" forKey:#"goalName"];
[newGoal setValue:#"Retirement" forKey:#"goalType"];
[self updateOutlineView];
}
break;
case 2:
{
[newGoal setValue:#"New Goal" forKey:#"goalName"];
[newGoal setValue:#"Education" forKey:#"goalType"];
[self updateOutlineView];
}
break;
case 3:
NSLog(#"You selected Item number 3");
break;
case 4:
NSLog(#"You selected Item number 4");
break;
default:
break;
}
NSWindow *w = [[self outlineView] window];
BOOL endEdit = [w makeFirstResponder:w];
if (!endEdit) {
return;
}
NSUInteger row = [[self outlineView] rowForItem:newGoal];
[[self outlineView] scrollRowToVisible:row];
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:row];
[[self outlineView] selectRowIndexes:indexSet byExtendingSelection:NO];
[[self outlineView] editColumn:0
row:row
withEvent:nil
select:YES];
NSError *anyError = nil;
BOOL success = [[self myContext] save:&anyError];
if (!success) {
NSLog(#"Error = %#", anyError);
}
}
}
- (BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
{
return YES;
}
- (void)alertEnded:(NSAlert *)alert
code:(int)choice
context:(void *)v
{
if (choice == NSAlertDefaultReturn) {
NSManagedObject *selectedGoal = [[self outlineView] itemAtRow:[[self outlineView] selectedRow]];
[[self myContext] deleteObject:selectedGoal];
NSError *anyError = nil;
BOOL success = [[self myContext] save:&anyError];
if (!success) {
NSLog(#"Error = %#", anyError);
}
[self updateOutlineView];
}
}
#end
Any attempt to do make the field editable within the current pass through the run loop will fail. What you need to do is to cue the selection up for the next time around the loop. Something like this:
[self performSelector:#selector(selectText:) withObject:textField afterDelay:0];
You might want to do something other than selectText on a textfield, but the technique is what you need.
I am trying to implement an undo/redo method using NSUndoManager. I have asked other questions on this, but am still stuck.
Where I am at the moment is as follows:
.h
NSUndoManager *undoManager;
#property(nonatomic,retain) NSUndoManager *undoManager;
.m
#synthesize undoManager;
[undoManager setLevelsOfUndo:99];
viewdidload:
NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
[dnc addObserver:self selector:#selector(undoButtonTapped) name:#"undo" object:nil];
[dnc addObserver:self selector:#selector(redoButtonTapped) name:#"redo" object:nil];
- (void)resetTheImage:(UIImage*)image
{
NSLog(#"%s", __FUNCTION__);
// image = savedImage.image;
if (image != drawImage.image)
{
[[undoManager prepareWithInvocationTarget:self] resetTheImage];
image = drawImage.image ;
} else {
NSLog(#"That didn't work");
}
}
- (void)undoButtonTapped {
NSLog(#"%s", __FUNCTION__);
[undoManager undo];
}
I get "That didn't work"...
I would appreciate help. I will post the answer to my original question when I figure out what I'm doing wrong.
---EDIT---
I have changed resetTheImage as follows:
- (void)resetTheImage:(UIImage*)image
{
NSLog(#"%s", __FUNCTION__);
image = savedImage.image;
if (image != drawImage.image)
{
drawImage.image = image;
savedImage.image = image;
NSLog(#"undo image");
[[self.undoManager prepareWithInvocationTarget:drawImage.image] image];
} else {
NSLog(#"same image");
savedImage.image = image;
}
}
However, confusion rains - it may help if someone (Brad?, Justin?) can provide a bullet point list of the steps I need to take to get this working. For example:
. Add notifications in ...
. Trigger notifications....
. Have undo /redo buttons point to...
. What methods/functions I really need to build..
....
I wish SO would allow me to give you more points than 1..
(It doesn't help that my "o" key is getting wonky)
It does help that I had a baby granddaughter yesterday :))))
First, I want to thank everyone for any/all assistance. I solved this finally although I'm not sure if it's the best solution.
I made a UIView called from the UIViewController. The controls (colors and brushes) remain in the VC. The drawing methods move to the View Method.
The View Method calls a Drawing method to actually perform the draw, and the View method controls the undo/redo.
Here are some code snippets:
-(void)undoButtonClicked
{
//NSLog(#"%s", __FUNCTION__);
if ([self.currentArray count] == 0) {
//nothing to undo
return;
}
DrawingPath *undonePath = [self.currentArray lastObject];
[self.currentArray removeLastObject];
[self.redoStack addObject:undonePath];
[self setNeedsDisplay];
}
-(void)redoButtonClicked
{
//NSLog(#"%s", __FUNCTION__);
if ([self.redoStack count] == 0) {
// nothing to redo
return;
}
DrawingPath *redonePath = [self.redoStack lastObject];
[self.redoStack removeLastObject];
[self.currentArray addObject:redonePath];
[self setNeedsDisplay];
}
Let me know if anyone wants clarification. Thanks all again..
UPDATE as requested:
These are some headers:
DrawingViewController *mvc;
NSMutableArray *pathArray;
NSMutableArray *colorArray;
NSMutableArray *bufferArray;
NSMutableArray *currentArray;
UIBezierPath *myPath;
NSString *brushSize;
CGPoint lastPoint;
int colorIndex;
NSString *colorKey;
SoundEffect *erasingSound;
SoundEffect *selectSound;
BOOL swiped;
int moved;
UIColor *currentColor;
NSString *result;
}
#property(nonatomic,assign) NSInteger undoSteps;
#property (strong, nonatomic) NSString *result;
#property (strong,nonatomic) UIColor *currentColor;
#property (strong,nonatomic) NSMutableArray *currentArray;
#property (strong,nonatomic) NSMutableArray *bufferArray;
#property (strong,nonatomic) DrawingPath *currentColoredPath;
#property (strong,nonatomic) NSMutableArray *redoStack;
#property (strong, nonatomic) NSString *colorKey;
and here are some more of the methods.. The currentArray then keeps track of points, brush and color in a sort of stack. Undo removes from the stack, and adds into a temp stack that can be used to Redo.
-(void)undoButtonClicked
{
//NSLog(#"%s", __FUNCTION__);
if ([self.currentArray count] == 0) {
//nothing to undo
return;
}
DrawingPath *undonePath = [self.currentArray lastObject];
[self.currentArray removeLastObject];
[self.redoStack addObject:undonePath];
[self setNeedsDisplay];
}
-(void)redoButtonClicked
{
//NSLog(#"%s", __FUNCTION__);
if ([self.redoStack count] == 0) {
// nothing to redo
return;
}
DrawingPath *redonePath = [self.redoStack lastObject];
[self.redoStack removeLastObject];
[self.currentArray addObject:redonePath];
[self setNeedsDisplay];
}
#pragma mark - Touch Methods
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//NSLog(#"%s", __FUNCTION__);
self.currentColoredPath = [[DrawingPath alloc] init];
[self.currentColoredPath setColor:self.currentColor];
UITouch *touch= [touches anyObject];
[self.currentColoredPath.path moveToPoint:[touch locationInView:self]];
[self.currentArray addObject:self.currentColoredPath];
// Remove all paths from redo stack
[self.redoStack removeAllObjects];
lastPoint = [touch locationInView:self];
lastPoint.y -= 20;
if ([touch tapCount] == 2) {
[self alertOKCancelAction];
return;
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
//NSLog(#"%s", __FUNCTION__);
UITouch *touch = [touches anyObject];
[self.currentColoredPath.path addLineToPoint:[touch locationInView:self]];
[self setNeedsDisplay];
CGPoint currentPoint = [touch locationInView:self];
currentPoint.y -= 20;
lastPoint = currentPoint;
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//NSLog(#"%s", __FUNCTION__);
self.currentColoredPath = nil;
}