{"action":"created","issue":{"url":"https://api.github.com/repos/cappuccino/cappuccino/issues/2395","labels_url":"https://api.github.com/repos/cappuccino/cappuccino/issues/2395/labels{/name}","comments_url":"https://api.github.com/repos/cappuccino/cappuccino/issues/2395/comments","events_url":"https://api.github.com/repos/cappuccino/cappuccino/issues/2395/events","html_url":"https://github.com/cappuccino/cappuccino/pull/2395","id":115507578,"number":2395,"title":"Implementation of CPTrackingArea","user":{"login":"didierkorthoudt","id":2394110,"avatar_url":"https://avatars.githubusercontent.com/u/2394110?v=3","gravatar_id":"","url":"https://api.github.com/users/didierkorthoudt","html_url":"https://github.com/didierkorthoudt","followers_url":"https://api.github.com/users/didierkorthoudt/followers","following_url":"https://api.github.com/users/didierkorthoudt/following{/other_user}","gists_url":"https://api.github.com/users/didierkorthoudt/gists{/gist_id}","starred_url":"https://api.github.com/users/didierkorthoudt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/didierkorthoudt/subscriptions","organizations_url":"https://api.github.com/users/didierkorthoudt/orgs","repos_url":"https://api.github.com/users/didierkorthoudt/repos","events_url":"https://api.github.com/users/didierkorthoudt/events{/privacy}","received_events_url":"https://api.github.com/users/didierkorthoudt/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/cappuccino/cappuccino/labels/%23needs-improvement","name":"#needs-improvement","color":"d4c5f9"},{"url":"https://api.github.com/repos/cappuccino/cappuccino/labels/%23needs-unit-test","name":"#needs-unit-test","color":"fff37a"},{"url":"https://api.github.com/repos/cappuccino/cappuccino/labels/AppKit","name":"AppKit","color":"ededed"},{"url":"https://api.github.com/repos/cappuccino/cappuccino/labels/feature","name":"feature","color":"adcdff"}],"state":"open","locked":false,"assignee":{"login":"aparajita","id":22218,"avatar_url":"https://avatars.githubusercontent.com/u/22218?v=3","gravatar_id":"","url":"https://api.github.com/users/aparajita","html_url":"https://github.com/aparajita","followers_url":"https://api.github.com/users/aparajita/followers","following_url":"https://api.github.com/users/aparajita/following{/other_user}","gists_url":"https://api.github.com/users/aparajita/gists{/gist_id}","starred_url":"https://api.github.com/users/aparajita/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aparajita/subscriptions","organizations_url":"https://api.github.com/users/aparajita/orgs","repos_url":"https://api.github.com/users/aparajita/repos","events_url":"https://api.github.com/users/aparajita/events{/privacy}","received_events_url":"https://api.github.com/users/aparajita/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/cappuccino/cappuccino/milestones/4","html_url":"https://github.com/cappuccino/cappuccino/milestones/Someday","labels_url":"https://api.github.com/repos/cappuccino/cappuccino/milestones/4/labels","id":107283,"number":4,"title":"Someday","description":"","creator":{"login":"aparajita","id":22218,"avatar_url":"https://avatars.githubusercontent.com/u/22218?v=3","gravatar_id":"","url":"https://api.github.com/users/aparajita","html_url":"https://github.com/aparajita","followers_url":"https://api.github.com/users/aparajita/followers","following_url":"https://api.github.com/users/aparajita/following{/other_user}","gists_url":"https://api.github.com/users/aparajita/gists{/gist_id}","starred_url":"https://api.github.com/users/aparajita/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aparajita/subscriptions","organizations_url":"https://api.github.com/users/aparajita/orgs","repos_url":"https://api.github.com/users/aparajita/repos","events_url":"https://api.github.com/users/aparajita/events{/privacy}","received_events_url":"https://api.github.com/users/aparajita/received_events","type":"User","site_admin":false},"open_issues":92,"closed_issues":988,"state":"open","created_at":"2012-04-12T21:50:28Z","updated_at":"2015-12-05T15:09:04Z","due_on":null,"closed_at":null},"comments":48,"created_at":"2015-11-06T13:45:14Z","updated_at":"2015-12-11T04:20:16Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/cappuccino/cappuccino/pulls/2395","html_url":"https://github.com/cappuccino/cappuccino/pull/2395","diff_url":"https://github.com/cappuccino/cappuccino/pull/2395.diff","patch_url":"https://github.com/cappuccino/cappuccino/pull/2395.patch"},"body":"This PR introduces the CPTrackingArea class (mirroring Cocoa's NSTrackingArea) and a new mouseEntered, mouseExited, mouseMoved management in order to reduce spread mouse events.\r\n\r\nUsing CPTrackingArea is simple : if your CPView subclass needs to receive mouseEntered and/or mouseExited and/or mouseMoved, use CPView's addTrackingArea (usually, one does this in initWithFrame and/or awakeFromCib methods) and provide a valid CPTrackingArea object.\r\n\r\nSee Cocoa documentation for complete description. Please note that CPTrackingCursorUpdate option is not yet implemented.\r\n\r\nThis PR impacts those classes : \r\n- CPControl : addition of a simple CPTrackingArea object to receive mouseEntered and mouseExited\r\n- CPEvent : addition of a new event constructor (enterExitEventWithType) and a new accessor for getting the CPTrackingArea that fired the event\r\n- CPSplitView : addition of a simple CPTrackingArea object to receive mouseEntered, mouseExited and mouseMoved\r\n- CPTableHeaderView : addition of a simple CPTrackingArea object to receive mouseEntered, mouseExited and mouseMoved\r\n- CPView : addition of addTrackingArea, removeTrackingArea and trackingAreas methods\r\n- CPWindow : rewriting of the sendEvent method and addition of some private methods\r\n\r\nA simple test case has shown that less than 10% of mouse movement events were relevant with current processing and 100% with this PR.\r\n\r\nBecause this PR changes event management, you have to check if some of your CPView subclasses are overwriting mouseEntered, mouseExited and/or mouseMoved. If so, just add a tracking area like this one : \r\n\r\n```\r\n        [self addTrackingArea:[[CPTrackingArea alloc] initWithRect:CGRectMakeZero()\r\n                                                           options:CPTrackingMouseEnteredAndExited | CPTrackingMouseMoved | CPTrackingActiveInKeyWindow | CPTrackingInVisibleRect\r\n                                                             owner:self\r\n                                                          userInfo:nil]];\r\n```\r\n(omit the CPTrackingMouseMoved option if not needed)\r\n\r\nThe CPTrackingInVisibleRect will ensure that whenever your view frame changes, the tracking rect used remains synced.\r\n\r\nSome remarks : \r\n- owner can be whatever object you want if it implements mouseEntered, mouseExited and/or mouseMoved methods\r\n- you can pass a dictionary as userInfo and get it back via [[anEvent trackingArea] userInfo]\r\n- a view can have multiple tracking areas\r\n- a tracking area can't be attached to multiple views (Cocoa doesn't complain about this, Cappuccino does)\r\n"},"comment":{"url":"https://api.github.com/repos/cappuccino/cappuccino/issues/comments/163835440","html_url":"https://github.com/cappuccino/cappuccino/pull/2395#issuecomment-163835440","issue_url":"https://api.github.com/repos/cappuccino/cappuccino/issues/2395","id":163835440,"user":{"login":"aparajita","id":22218,"avatar_url":"https://avatars.githubusercontent.com/u/22218?v=3","gravatar_id":"","url":"https://api.github.com/users/aparajita","html_url":"https://github.com/aparajita","followers_url":"https://api.github.com/users/aparajita/followers","following_url":"https://api.github.com/users/aparajita/following{/other_user}","gists_url":"https://api.github.com/users/aparajita/gists{/gist_id}","starred_url":"https://api.github.com/users/aparajita/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aparajita/subscriptions","organizations_url":"https://api.github.com/users/aparajita/orgs","repos_url":"https://api.github.com/users/aparajita/repos","events_url":"https://api.github.com/users/aparajita/events{/privacy}","received_events_url":"https://api.github.com/users/aparajita/received_events","type":"User","site_admin":false},"created_at":"2015-12-11T04:20:15Z","updated_at":"2015-12-11T04:20:15Z","body":"Awesome work! I found a few bugs and some issues in the test app:\r\n\r\n- In Cocoa, if NSTrackingEnabledDuringMouseDrag is not on, mouseExit/cursorUpdate are sent when leaving a tracking area that the pointer was in when the drag started. This includes nested tracking areas. So if I'm in a tracking area and start a drag, when I drag out of the tracking area, mouseExit/cursorUpdate is sent. But otherwise no events are sent until the mouse button is released.\r\n\r\n- In Cocoa, if NSTrackingEnabledDuringMouseDrag is not on and I start a drag outside of a tracking area, drag into a tracking area, then release the mouse button, all tracking areas that the pointer are within that did not receive events during the drag receive events.\r\n\r\nFor these two issues, see the attached Cocoa app for reference. Try the scenarios I mentioned and watch the events received in the Xcode console.\r\n\r\n- In the test app, please add console logging of the events that are received by owners.\r\n\r\n- It isn't clear to me what the \"Click to add view\" button does. I see a view appear, which seems to have it's own tracking area with a different cursor, but the areas below that view still seem to receive mouseEnter/mouseExit. Is that what Cocoa would do? And once that button has been clicked, shouldn't it be disabled? There doesn't seem to be much point in adding more views.\r\n\r\n- One of the nested tracking areas should have an owner that implements cursorUpdate but does not set the cursor, so we can be sure the cursor does not change from the adjacent tracking area.\r\n\r\n- One of the nested tracking areas should have an owner that asks for cursor updates but does not implement cursorUpdate at all, so we can be sure the cursor will change to an arrow over that tracking area."}}