I want to scroll a scrollview based on the UIAccelerometer values. What is the best way to accomplish this?
Initially I set the content offset to a value based on the accelerometer values I get. Then on each scrollViewDidEndAnimating, I again set the content offset based on the acceleromter values. I understand that setContentOffset actually scrolls the scrollview with a uniform velocity without any acceleration. However this mechanism seems to be very jerky in scrolling the scrollview.
Any ideas will be appreciated.
Thanks and Regards
I did this once. sv is the scroll view.
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
if (sv.tracking || sv.decelerating) return;
CGPoint pt = sv.contentOffset;
pt.x += acceleration.x * 2;
pt.y -= acceleration.y * 2;
if (pt.x < 0) pt.x = 0;
if (pt.x > sv.contentSize.width - sv.frame.size.width) pt.x = sv.contentSize.width - sv.frame.size.width;
if (pt.y < 0) pt.y = 0;
if (pt.y > sv.contentSize.height - sv.frame.size.height) pt.y = sv.contentSize.height - sv.frame.size.height;
sv.contentOffset = pt;
}
Related
I'm currently implementing mouse input using Raw input.
The disadvantage though is, that pointer ballistic is not included. Unfortunately microsoft's website dealing with this topic is not online any more. Furthermore I can't find a function retrieving the pointer acceleration set in windows (maybe I'm too stupid).
How do I get the acceleration and how do I use it to calculate the new intuitive cursor position out of the raw x and y offset?
EDIT:
So concerning the documentation IInspectable posted in his comment, the code for calculating the acceleration would be:
long xPos = raw->data.mouse.lLastX;
long yPos = raw->data.mouse.lLastY;
int speed;
int acceleration[3];
SystemParametersInfo(SPI_GETMOUSESPEED, 0, &speed, 0);
SystemParametersInfo(SPI_GETMOUSE, 0, acceleration, 0);
if (acceleration[2] > 0 && acceleration[0] < abs(raw->data.mouse.lLastX))
xPos *= 2;
else if (acceleration[2] > 1 && acceleration[1] < abs(raw->data.mouse.lLastX))
xPos *= 2;
if (acceleration[2] > 0 && acceleration[0] < abs(raw->data.mouse.lLastX))
yPos *= 2;
else if (acceleration[2] > 1 && acceleration[1] < abs(raw->data.mouse.lLastX))
yPos *= 2;
xPos *= round((float)speed / 10.0f);
yPos *= round((float)speed / 10.0f);
Am I right, is this how to add acceleration to the raw mouse input?
Strange is, that when I retrieve acceleration with SystemParametersInfo and SPI_GETMOUSE the values stay at {6, 10, 1} even if I change the pointer acceleration in windows.
I have a single function that does this scaling, for an arbitrary delta (dq), and it is similar to yours. However, my experience is that Windows acceleration and pointer enhancement, in particular when there's DPI awareness to take into account, makes the mapping between RAWINPUT and what a corresponding WM_MOUSEMOVE would see, very tricky...
int ApplyMouseAcceleration(int dq)
{
auto absdq{ abs(dq) };
// based on https://msdn.microsoft.com/en-us/library/windows/desktop/ms646260(v=vs.85).aspx
if (MouseAccelerationparams[0] && absdq > MouseAccelerationparams[0])
{
dq *= 2;
if ((absdq > MouseAccelerationparams[1]) && (MouseAccelerationparams[2] == 2))
{
dq *= 2;
}
}
dq = (dq*MouseSpeed) / 10;
return dq;
}
I'm trying to dynamically add a border to a texture of mine. So far, I have a border at the top, and at the bottom. But struggling to get a left and right border. This is what I have so far:
var i = image;
var pixels : Color[] = i.GetPixels(0, 0, i.width, i.height, 0);
var br : int = 1;
for(var p = 0; p < pixels.Length; p++){
var b : int = 30;
//Bottom
if(p < i.width * b)
pixels[p] = new Color(1,0,0,1);
//Top
if(p > (i.height * i.width) - (i.width * b))
pixels[p] = new Color(1,0,0,1);
//int when a new row of pixels has began
if(p > i.width * br)
br++;
}
The pixels are read from bottom left, to top right. I just can't seem to get my head around the maths.
Thanks
Probably the easiest way to get x position of a pixel is to use modular operator (%), which returns the remainder.
Here is a code calculating the x position and setting the border based on that:
// Left
if(p % i.width < b)
pixels[p] = new Color(1,0,0,1);
// right
if(p % i.width > i.width - b)
pixels[p] = new Color(1,0,0,1);
I've made several rectangles by using a loop.
The color of the rectangles are provided from an array.
I want on clicking one of the rectangles, that background fills with the color I selected.
I'm new to processing so i'm a bit confused on how to do it.
color[] backgrounds = {#e8be55, #ff8827, #eb5051, #00b4cc, #005f6b, #7c6753, #edeaee};
int bgLength = backgrounds.length;
int xPos;
int yPos;
int size;
void setup(){
background(255);
size(1024, 768);
}
void draw(){
size = 40;
xPos = guide + 10;
yPos = 167;
for(int i = 0; i < bgLength; i++) {
noStroke();
fill(backgrounds[i]);
rect(xPos, yPos, size, size);
xPos = xPos + size + 4;
if(xPos>180){
xPos = guide + 10;
yPos += size + 4;
}
}
}
Thanks.
You need to check the bounds. First I suggest you organize the variables a bit.
For example some variables never change(so there's no reason to assign them in draw()).
This should make it easier to see what the coordinates are.
I suggest this:
color[] backgrounds = {#e8be55, #ff8827, #eb5051, #00b4cc, #005f6b, #7c6753, #edeaee};
int bgLength = backgrounds.length;
int xOffset = 10;
int yOffset = 167;
int xPos;
int yPos;
int size = 40;
int guide = 10;
int cols = 4;//4 columns
color selectedBackground = backgrounds[backgrounds.length-1];//default to last element in the list/array
void setup(){
background(255);
size(1024, 768);
noStroke();
}
void draw(){
background(selectedBackground);
for(int i = 0; i < bgLength; i++) {
xPos = xOffset + ((i % cols) * (size+guide));//since % is returns the remainder of division, we use it to compute x position in the grid
yPos = yOffset + ((i / cols) * (size+guide));//and we divide by the number of columns to compute the y position in the grid
fill(backgrounds[i]);
//check if a box is clicked
if((mouseX >= xPos && mouseX <= xPos+size) && //check horizontal bounds(left/right)
(mouseY >= yPos && mouseY <= yPos+size)){ //check vertical bounds(top/bottom)
if(mousePressed){//if mouse is over/within a boxes bounds and clicked
selectedBackground = backgrounds[i];//set the colour based on id
}else{//just hovering
fill(backgrounds[i],127);//draw transparent colour, just to high light selection, not actually needed, but now an easy option
}
}
rect(xPos, yPos, size, size);//we draw at the end because the fill colour might have changed if a box was hovered
}
}
You can run a javascript demo bellow. (Although there are minor differences in syntax, the core concept is the same):
var backgrounds;// = [color('#e8be55'), color('#ff8827'), color('#eb5051'), color('#00b4cc'), color('#005f6b'), color('#7c6753'), color('#edeaee')];
var bgLength;// = backgrounds.length;
var xOffset = 10;
var yOffset = 67;
var xPos = 0;
var yPos = 0;
var ssize = 40;
var guide = 10;
var cols = 4;//4 columns
var selectedBackground;// = backgrounds[backgrounds.length-1];//default to last element in the list/array
function setup(){
createCanvas(1024, 768);noStroke();
backgrounds = [color('#e8be55'), color('#ff8827'), color('#eb5051'), color('#00b4cc'), color('#005f6b'), color('#7c6753'), color('#edeaee')];
bgLength = backgrounds.length;
selectedBackground = backgrounds[backgrounds.length-1];//default to last element in the list/array
}
function draw(){
background(selectedBackground);
for(var i = 0; i < bgLength; i++) {
xPos = xOffset + ((i % cols) * (ssize+guide));//since % is returns the remainder of division, we use it to compute x position in the grid
yPos = yOffset + (floor(i / cols) * (ssize+guide));//and we divide by the number of columns to compute the y position in the grid
fill(backgrounds[i]);
//check if a box is clicked
if((mouseX >= xPos && mouseX <= xPos+ssize) && //check horizontal bounds(left/right)
(mouseY >= yPos && mouseY <= yPos+ssize)){ //check vertical bounds(top/bottom)
if(isMousePressed){//if mouse is over/within a boxes bounds and clicked
selectedBackground = backgrounds[i];//set the colour based on id
}else{//just hovering
fill(backgrounds[i].rgba[0]+50,backgrounds[i].rgba[1]+50,backgrounds[i].rgba[2]+50);//draw transparent colour, just to high light selection, not actually needed, but now an easy option
}
}
rect(xPos, yPos, ssize, ssize);//we draw at the end because the fill colour might have changed if a box was hovered
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.4/p5.min.js"></script>
I'm having a problem with Cocos2D. I'm trying to have a sprite movable on screen (which I've been able to do), but stop it from being clipped by the edge of the screen.
If I'm correct, sprites are imported to the layer as rectangles (spriteWithFile:#"filename.ext" rect:CGRectMake(0, 0, X, Y);).
The only thing I've been able to figure out so far is to setup my code to detect if the rectangle of the sprite has gone outside of the "background" layer, and adjust it accordingly if it does.
This is what I have so far, but it doesn't seem to be working correctly:
- (void)panForTranslation:(CGPoint)translation {
CGSize winSize = [CCDirector sharedDirector].winSize;
float maxX = winSize.width - selSprite.contentSize.width/2;
float minX = selSprite.contentSize.width/2;
float maxY = winSize.height - selSprite.contentSize.height/2;
float minY = selSprite.contentSize.height/2;
if (selSprite.position.x > maxX)
{
selSprite.position = ccp(maxX, selSprite.position.y);
}
else if (selSprite.position.x < minX)
{
selSprite.position = ccp(minX, selSprite.position.y);
}
if (selSprite.position.y > maxY)
{
selSprite.position = ccp(selSprite.position.x, maxY);
}
else if (selSprite.position.y < minY)
{
selSprite.position = ccp(selSprite.position.x, minY);
}
CGPoint newPos = ccpAdd(selSprite.position, translation);
selSprite.position = newPos;
}
Is there something completely obvious that I'm missing? My sprites keep moving off screen if I drag them, and I can't figure it out for the life of me.
Try this:
float maxX = winSize.width - selSprite.contentSize.width/2;
float minX = selSprite.contentSize.width/2;
float maxY = ...;
float minY = ...;
if (selSprinte.position.x > maxX)
{
selSprite.position = ccp(maxX, selSprite.position.y);
}
else if (selSprinte.position.x < minX)
{
selSprite.position = ccp(minX, selSprite.position.y);
}
if (selSprinte.position.y > maxY)
{
selSprite.position = ccp(selSprite.position.x, maxY);
}
else if (selSprinte.position.y < minY)
{
selSprite.position = ccp(selSprite.position.x, minY);
}
and add the same code for y.
I have a sprite which is larger in size than the screen size. I used this:
node.position = CGPointMake(MIN(MAX(size.width - node.contentSize.width /2,node.position.x), node.contentSize.width / 2),
MIN(MAX(size.height - node.contentSize.height/2,node.position.y), node.contentSize.height / 2));
Using this code, my sprite corner was either outside the screen or at the edge of the screen which helped me to see my complete image by scrolling it.
Here:
node = CCSprite
size = [[CCDirector sharedDirector] winSize]
Is it possible to get the frame of a NSStatusItem after I've added it to the status bar in Cocoa? When my app is launched, I am adding an item to the system status bar, and would like to know where it was positioned, is possible.
The following seems to work - I have seen similar solutions for iOS applications and supposedly they permit submission to the app store because you are still using standard SDK methods.
NSRect frame = [[statusBarItem valueForKey:#"window"] frame];
With 10.10, NSStatusItem has a button property that be used to get the status item position without setting a custom view.
NSStatusBarButton *statusBarButton = [myStatusItem button];
NSRect rectInWindow = [statusBarButton convertRect:[statusBarButton bounds] toView:nil];
NSRect screenRect = [[statusBarButton window] convertRectToScreen:rectInWindow];
NSLog(#"%#", NSStringFromRect(screenRect));
You can use statusItem.button.superview?.window?.frame in swift
If you have set a custom view on the status item:
NSRect statusRect = [[statusItem view] frame];
NSLog(#"%#", [NSString stringWithFormat:#"%.1fx%.1f",statusRect.size.width, statusRect.size.height]);
Otherwise I don't think it's possible using the available and documented APIs.
Edit: Incorporated comments.
It's possible to do this without any private API. Here's a category for NSScreen. This uses image analysis to locate the status item's image on the menu bar. Fortunately, computers are really fast. :)
As long as you know what the status item's image looks like, and can pass it in as an NSImage, this method should find it.
Works for dark mode as well as regular mode. Note that the image you pass in must be black. Colored images will probably not work so well.
#implementation NSScreen (LTStatusItemLocator)
// Find the location of IMG on the screen's status bar.
// If the image is not found, returns NSZeroPoint
- (NSPoint)originOfStatusItemWithImage:(NSImage *)IMG
{
CGColorSpaceRef csK = CGColorSpaceCreateDeviceGray();
NSPoint ret = NSZeroPoint;
CGDirectDisplayID screenID = 0;
CGImageRef displayImg = NULL;
CGImageRef compareImg = NULL;
CGRect screenRect = CGRectZero;
CGRect barRect = CGRectZero;
uint8_t *bm_bar = NULL;
uint8_t *bm_bar_ptr;
uint8_t *bm_compare = NULL;
uint8_t *bm_compare_ptr;
size_t bm_compare_w, bm_compare_h;
BOOL inverted = NO;
int numberOfScanLines = 0;
CGFloat *meanValues = NULL;
int presumptiveMatchIdx = -1;
CGFloat presumptiveMatchMeanVal = 999;
// If the computer is set to Dark Mode, set the "inverted" flag
NSDictionary *globalPrefs = [[NSUserDefaults standardUserDefaults] persistentDomainForName:NSGlobalDomain];
id style = globalPrefs[#"AppleInterfaceStyle"];
if ([style isKindOfClass:[NSString class]]) {
inverted = (NSOrderedSame == [style caseInsensitiveCompare:#"dark"]);
}
screenID = (CGDirectDisplayID)[self.deviceDescription[#"NSScreenNumber"] integerValue];
screenRect = CGDisplayBounds(screenID);
// Get the menubar rect
barRect = CGRectMake(0, 0, screenRect.size.width, 22);
displayImg = CGDisplayCreateImageForRect(screenID, barRect);
if (!displayImg) {
NSLog(#"Unable to create image from display");
CGColorSpaceRelease(csK);
return ret; // I would normally use goto(bail) here, but this is public code so let's not ruffle any feathers
}
size_t bar_w = CGImageGetWidth(displayImg);
size_t bar_h = CGImageGetHeight(displayImg);
// Determine scale factor based on the CGImageRef we got back from the display
CGFloat scaleFactor = (CGFloat)bar_h / (CGFloat)22;
// Greyscale bitmap for menu bar
bm_bar = malloc(1 * bar_w * bar_h);
{
CGContextRef bmCxt = NULL;
bmCxt = CGBitmapContextCreate(bm_bar, bar_w, bar_h, 8, 1 * bar_w, csK, kCGBitmapAlphaInfoMask&kCGImageAlphaNone);
// Draw the menu bar in grey
CGContextDrawImage(bmCxt, CGRectMake(0, 0, bar_w, bar_h), displayImg);
uint8_t minVal = 0xff;
uint8_t maxVal = 0x00;
// Walk the bitmap
uint64_t running = 0;
for (int yi = bar_h / 2; yi == bar_h / 2; yi++)
{
bm_bar_ptr = bm_bar + (bar_w * yi);
for (int xi = 0; xi < bar_w; xi++)
{
uint8_t v = *bm_bar_ptr++;
if (v < minVal) minVal = v;
if (v > maxVal) maxVal = v;
running += v;
}
}
running /= bar_w;
uint8_t threshold = minVal + ((maxVal - minVal) / 2);
//threshold = running;
// Walk the bitmap
bm_bar_ptr = bm_bar;
for (int yi = 0; yi < bar_h; yi++)
{
for (int xi = 0; xi < bar_w; xi++)
{
// Threshold all the pixels. Values > 50% go white, values <= 50% go black
// (opposite if Dark Mode)
// Could unroll this loop as an optimization, but probably not worthwhile
*bm_bar_ptr = (*bm_bar_ptr > threshold) ? (inverted?0x00:0xff) : (inverted?0xff:0x00);
bm_bar_ptr++;
}
}
CGImageRelease(displayImg);
displayImg = CGBitmapContextCreateImage(bmCxt);
CGContextRelease(bmCxt);
}
{
CGContextRef bmCxt = NULL;
CGImageRef img_cg = NULL;
bm_compare_w = scaleFactor * IMG.size.width;
bm_compare_h = scaleFactor * 22;
// Create out comparison bitmap - the image that was passed in
bmCxt = CGBitmapContextCreate(NULL, bm_compare_w, bm_compare_h, 8, 1 * bm_compare_w, csK, kCGBitmapAlphaInfoMask&kCGImageAlphaNone);
CGContextSetBlendMode(bmCxt, kCGBlendModeNormal);
NSRect imgRect_og = NSMakeRect(0,0,IMG.size.width,IMG.size.height);
NSRect imgRect = imgRect_og;
img_cg = [IMG CGImageForProposedRect:&imgRect context:nil hints:nil];
CGContextClearRect(bmCxt, imgRect);
CGContextSetFillColorWithColor(bmCxt, [NSColor whiteColor].CGColor);
CGContextFillRect(bmCxt, CGRectMake(0,0,9999,9999));
CGContextScaleCTM(bmCxt, scaleFactor, scaleFactor);
CGContextTranslateCTM(bmCxt, 0, (22. - IMG.size.height) / 2.);
// Draw the image in grey
CGContextSetFillColorWithColor(bmCxt, [NSColor blackColor].CGColor);
CGContextDrawImage(bmCxt, imgRect, img_cg);
compareImg = CGBitmapContextCreateImage(bmCxt);
CGContextRelease(bmCxt);
}
{
// We start at the right of the menu bar, and scan left until we find a good match
int numberOfScanLines = barRect.size.width - IMG.size.width;
bm_compare = malloc(1 * bm_compare_w * bm_compare_h);
// We use the meanValues buffer to keep track of how well the image matched for each point in the scan
meanValues = calloc(sizeof(CGFloat), numberOfScanLines);
// Walk the menubar image from right to left, pixel by pixel
for (int scanx = 0; scanx < numberOfScanLines; scanx++)
{
// Optimization, if we recently found a really good match, bail on the loop and return it
if ((presumptiveMatchIdx >= 0) && (scanx > (presumptiveMatchIdx + 5))) {
break;
}
CGFloat xOffset = numberOfScanLines - scanx;
CGRect displayRect = CGRectMake(xOffset * scaleFactor, 0, IMG.size.width * scaleFactor, 22. * scaleFactor);
CGImageRef displayCrop = CGImageCreateWithImageInRect(displayImg, displayRect);
CGContextRef compareCxt = CGBitmapContextCreate(bm_compare, bm_compare_w, bm_compare_h, 8, 1 * bm_compare_w, csK, kCGBitmapAlphaInfoMask&kCGImageAlphaNone);
CGContextSetBlendMode(compareCxt, kCGBlendModeCopy);
// Draw the image from our menubar
CGContextDrawImage(compareCxt, CGRectMake(0,0,IMG.size.width * scaleFactor, 22. * scaleFactor), displayCrop);
// Blend mode difference is like an XOR
CGContextSetBlendMode(compareCxt, kCGBlendModeDifference);
// Draw the test image. Because of blend mode, if we end up with a black image we matched perfectly
CGContextDrawImage(compareCxt, CGRectMake(0,0,IMG.size.width * scaleFactor, 22. * scaleFactor), compareImg);
CGContextFlush(compareCxt);
// Walk through the result image, to determine overall blackness
bm_compare_ptr = bm_compare;
for (int i = 0; i < bm_compare_w * bm_compare_h; i++)
{
meanValues[scanx] += (CGFloat)(*bm_compare_ptr);
bm_compare_ptr++;
}
meanValues[scanx] /= (255. * (CGFloat)(bm_compare_w * bm_compare_h));
// If the image is very dark, it matched well. If the average pixel value is < 0.07, we consider this
// a presumptive match. Mark it as such, but continue looking to see if there's an even better match.
if (meanValues[scanx] < 0.07) {
if (meanValues[scanx] < presumptiveMatchMeanVal) {
presumptiveMatchMeanVal = meanValues[scanx];
presumptiveMatchIdx = scanx;
}
}
CGImageRelease(displayCrop);
CGContextRelease(compareCxt);
}
}
// After we're done scanning the whole menubar (or we bailed because we found a good match),
// return the origin point.
// If we didn't match well enough, return NSZeroPoint
if (presumptiveMatchIdx >= 0) {
ret = CGPointMake(CGRectGetMaxX(self.frame), CGRectGetMaxY(self.frame));
ret.x -= (IMG.size.width + presumptiveMatchIdx);
ret.y -= 22;
}
CGImageRelease(displayImg);
CGImageRelease(compareImg);
CGColorSpaceRelease(csK);
if (bm_bar) free(bm_bar);
if (bm_compare) free(bm_compare);
if (meanValues) free(meanValues);
return ret;
}
#end
you can hack the window ivar like this :
#interface NSStatusItem (Hack)
- (NSRect)hackFrame;
#end
#implementation NSStatusItem (Hack)
- (NSRect)hackFrame
{
int objSize = class_getInstanceSize( [NSObject class] ) ;
id * _ffWindow = (void *)self + objSize + sizeof(NSStatusBar*) + sizeof(CGFloat) ;
NSWindow * window = *_ffWindow ;
return [window frame] ;
}
#end
This is useful for status items without a custom view.
Tested on Lion