mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-22 18:11:06 +00:00
Additional NSScroller implementation.
Fix locking/unlocking of focus for view hierarchy. Numerous bug fixes. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@2255 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
4047b4b412
commit
1957d087a5
8 changed files with 219 additions and 70 deletions
40
ChangeLog
40
ChangeLog
|
@ -1,4 +1,32 @@
|
|||
Fri Mar 14 18:23:18 1997 Ovidiu Predescu <ovidiu@bx.logicnet.ro>
|
||||
Thu Mar 20 10:40:51 1997 GNUstep Development <gnustep@net-community.com>
|
||||
|
||||
* Source/NSControl.m (-copyWithZone:): Copy the object instead of
|
||||
allocating so that instance variable values are copied. Retain
|
||||
the cell because it will be released when we set a new one.
|
||||
(-drawCell:, -drawCellInside:): Lock and unlock the focus
|
||||
when drawing the cell.
|
||||
* Source/NSImage.m (_base_name, extension): Delete functions;
|
||||
functionality is now provided by NSString.
|
||||
(+imageNamed:) Use NSString methods instead of local functions for
|
||||
obtaining base name and extension. Check if extension is one of
|
||||
the image types before deleting.
|
||||
(-useFromFile:): Use NSString methods instead of local functions
|
||||
for obtaining the extension.
|
||||
* Source/NSScroller.m (-setFloatValue:knobProportion:): Set knob
|
||||
proportion first before setting float value.
|
||||
(-drawRect:): Remove method.
|
||||
(-drawParts): Flush window.
|
||||
(-trackKnob:): Correct position of knob relative to pointer.
|
||||
(-trackScrollButtons:): Fill out implementation.
|
||||
(-mouseDown:): Lock and unlock focus.
|
||||
* Source/NSTextField.m (-setTextCursor:, -copyWithZone:): New methods.
|
||||
* Source/NSTextFieldCell.m (-initTextCell:): By default
|
||||
it draws the background.
|
||||
* Source/NSView.m (-ancestoreSharedWithView:): Implement.
|
||||
(-lockFocus, -unlockFocus): Make sure our superview locks or unlocks
|
||||
the focus before us.
|
||||
|
||||
Fri Mar 14 18:23:18 1997 Ovidiu Predescu <ovidiu@net-community.com>
|
||||
|
||||
* Flush the view's window after a redraw.
|
||||
* Source/NSButton.m (-mouseDown:): Likewise.
|
||||
|
@ -28,7 +56,7 @@ Wed Mar 5 17:43:34 1997 GNUstep Development <gnustep@net-community.com>
|
|||
* Headers/gnustep/gui/nsimage-tiff.h: Include gnustep-gui config.
|
||||
* Source/tiff.m: Include header file.
|
||||
|
||||
Tue Mar 4 18:05:24 1997 Ovidiu Predescu <ovidiu@bx.logicnet.ro>
|
||||
Tue Mar 4 18:05:24 1997 Ovidiu Predescu <ovidiu@net-community.com>
|
||||
|
||||
* Source/NSFont.m (-minimumAdvancement): New method.
|
||||
* Source/NSButton.m (-initWithFrame:): Use an autoreleased cell.
|
||||
|
@ -118,7 +146,7 @@ Tue Mar 4 09:28:57 1997 GNUstep Development <gnustep@net-community.com>
|
|||
* Source/NSBundle.m (+imageNamed:): Create a bundle with
|
||||
gnustep library install path for searching system resources.
|
||||
|
||||
Mon Feb 17 19:30:50 1997 Ovidiu Predescu <ovidiu@bx.logicnet.ro>
|
||||
Mon Feb 17 19:30:50 1997 Ovidiu Predescu <ovidiu@net-community.com>
|
||||
|
||||
* Source/NSButton.m: New methods -setAlignment: and -alignment,
|
||||
setIntValue:, setFloatValue:, setDoubleValue:, setAlignment:,
|
||||
|
@ -133,7 +161,7 @@ Mon Feb 17 19:30:50 1997 Ovidiu Predescu <ovidiu@bx.logicnet.ro>
|
|||
way in which setIntValue:, setFloatValue: and setDoubleValue: work.
|
||||
Commented out a point conversion that works wrong (why?).
|
||||
|
||||
Sat Feb 15 23:12:35 1997 Ovidiu Predescu <ovidiu@bx.logicnet.ro>
|
||||
Sat Feb 15 23:12:35 1997 Ovidiu Predescu <ovidiu@net-community.com>
|
||||
|
||||
* Major reorganization of header files. Types and constants were moved
|
||||
in the files they belong (too many to enumerate here). Each header
|
||||
|
@ -175,7 +203,7 @@ Thu Feb 6 19:31:54 1997 GNUstep Development <gnustep@net-community.com>
|
|||
* NSView.m: Don't use -isKindOfClass: because it isn't working
|
||||
as we expect with the backend classes doing a +poseAs:
|
||||
|
||||
Mon Feb 10 17:23:06 1997 Ovidiu Predescu <ovidiu@bx.logicnet.ro>
|
||||
Mon Feb 10 17:23:06 1997 Ovidiu Predescu <ovidiu@net-community.com>
|
||||
|
||||
* Source/NSFont.m: Completely reworked. Get the default fonts using
|
||||
the NSUserDefaults class instead of hard-coding them. Almost all the
|
||||
|
@ -267,7 +295,7 @@ Thu Jan 23 15:10:13 1997 Scott Christley <scottc@net-community.com>
|
|||
defined in NSApplication.
|
||||
* Source/NSTextFieldCell.m (-initWithFrame:): Bezeled by default.
|
||||
|
||||
Tue Jan 14 9:33:04 1997 Ovidiu Predescu <ovidiu@bx.logicnet.ro>
|
||||
Tue Jan 14 9:33:04 1997 Ovidiu Predescu <ovidiu@net-community.com>
|
||||
|
||||
* Source/Functions.m: Exclude from compiling the NSLog functions when
|
||||
working with libFoundation.
|
||||
|
|
|
@ -104,11 +104,12 @@ NSString *NSControlTextDidChangeNotification = @"NSControlTextDidChangeNotificat
|
|||
- copyWithZone:(NSZone *)zone
|
||||
{
|
||||
id c;
|
||||
c = NSAllocateObject (isa, 0, zone);
|
||||
c = NSCopyObject (self, 0, zone);
|
||||
|
||||
NSLog(@"NSControl: copyWithZone\n");
|
||||
|
||||
// make sure the new copy also has a new copy of the cell
|
||||
[cell retain];
|
||||
[c setCell: [[cell copy] autorelease]];
|
||||
return c;
|
||||
}
|
||||
|
@ -296,12 +297,22 @@ right:(unsigned)rightDigits
|
|||
//
|
||||
- (void)drawCell:(NSCell *)aCell
|
||||
{
|
||||
if (cell == aCell) [cell drawWithFrame:bounds inView:self];
|
||||
if (cell == aCell)
|
||||
{
|
||||
[self lockFocus];
|
||||
[cell drawWithFrame:bounds inView:self];
|
||||
[self unlockFocus];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)drawCellInside:(NSCell *)aCell
|
||||
{
|
||||
if (cell == aCell) [cell drawInteriorWithFrame:bounds inView:self];
|
||||
if (cell == aCell)
|
||||
{
|
||||
[self lockFocus];
|
||||
[cell drawInteriorWithFrame:bounds inView:self];
|
||||
[self unlockFocus];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)selectCell:(NSCell *)aCell
|
||||
|
|
|
@ -72,30 +72,6 @@ static NSMutableDictionary* nameDict;
|
|||
|
||||
NSArray *iterate_reps_for_types(NSArray *imageReps, SEL method);
|
||||
|
||||
/* (NSString doesn't do these yet) */
|
||||
/* Strip the extension from a name */
|
||||
#define BASENAME(str) ((strrchr(str, '/')) ? strrchr(str, '/')+1 : str)
|
||||
static NSString *
|
||||
_base_name(NSString *name)
|
||||
{
|
||||
return [NSString stringWithCString: BASENAME([name cString])];
|
||||
}
|
||||
|
||||
/* Get the extension from a name */
|
||||
static NSString *
|
||||
extension(NSString *name)
|
||||
{
|
||||
const char* cname;
|
||||
char *s;
|
||||
|
||||
cname = [name cString];
|
||||
s = strrchr(cname, '.');
|
||||
if (s > strrchr(cname, '/'))
|
||||
return [NSString stringWithCString:s+1];
|
||||
else
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* Find the rep_data_t holding a representation */
|
||||
rep_data_t
|
||||
repd_for_rep(NSArray *_reps, NSImageRep *rep)
|
||||
|
@ -171,27 +147,39 @@ set_repd_for_rep(NSMutableArray *_reps, NSImageRep *rep, rep_data_t *new_repd)
|
|||
NSString* ext;
|
||||
NSString* path = nil;
|
||||
NSBundle* main;
|
||||
NSArray *array;
|
||||
NSString *the_name = aName;
|
||||
main = [NSBundle mainBundle];
|
||||
ext = extension(aName);
|
||||
ext = [aName pathExtension];
|
||||
|
||||
/* Check if extension is one of the image types */
|
||||
array = [self imageFileTypes];
|
||||
if ([array indexOfObject: ext] != NSNotFound)
|
||||
{
|
||||
/* Extension is one of the image types
|
||||
So remove from the name */
|
||||
the_name = [aName stringByDeletingPathExtension];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise extension is not an image type
|
||||
So leave it alone */
|
||||
the_name = aName;
|
||||
ext = nil;
|
||||
}
|
||||
|
||||
NSDebugLog(@"search locally\n");
|
||||
NSDebugLog(@"extension is %s\n", [ext cString]);
|
||||
/* First search locally */
|
||||
if (ext)
|
||||
path = [main pathForResource: aName ofType: ext];
|
||||
path = [main pathForResource: the_name ofType: ext];
|
||||
else
|
||||
{
|
||||
id o, e;
|
||||
NSArray* array;
|
||||
|
||||
array = [self imageFileTypes];
|
||||
if (!array)
|
||||
NSDebugLog(@"array is nil\n");
|
||||
e = [array objectEnumerator];
|
||||
while ((o = [e nextObject]))
|
||||
{
|
||||
NSDebugLog(@"extension %s\n", [o cString]);
|
||||
path = [main pathForResource:aName
|
||||
path = [main pathForResource:the_name
|
||||
ofType: o];
|
||||
if ([path length] != 0)
|
||||
break;
|
||||
|
@ -204,7 +192,7 @@ set_repd_for_rep(NSMutableArray *_reps, NSImageRep *rep, rep_data_t *new_repd)
|
|||
NSBundle *system = [NSBundle bundleWithPath: gnustep_libdir];
|
||||
|
||||
if (ext)
|
||||
path = [system pathForResource: aName
|
||||
path = [system pathForResource: the_name
|
||||
ofType: ext
|
||||
inDirectory: NSImage_PATH];
|
||||
else
|
||||
|
@ -218,7 +206,7 @@ set_repd_for_rep(NSMutableArray *_reps, NSImageRep *rep, rep_data_t *new_repd)
|
|||
e = [array objectEnumerator];
|
||||
while ((o = [e nextObject]))
|
||||
{
|
||||
path = [system pathForResource: aName
|
||||
path = [system pathForResource: the_name
|
||||
ofType: o
|
||||
inDirectory: NSImage_PATH];
|
||||
if ([path length] != 0)
|
||||
|
@ -231,7 +219,9 @@ set_repd_for_rep(NSMutableArray *_reps, NSImageRep *rep, rep_data_t *new_repd)
|
|||
{
|
||||
NSImage* image = [[NSImage alloc] initByReferencingFile:path];
|
||||
if (image)
|
||||
[image setName:_base_name(path)];
|
||||
[image setName: [[path lastPathComponent]
|
||||
stringByDeletingPathExtension]];
|
||||
[nameDict setObject: image forKey: [image name]];
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
@ -665,7 +655,7 @@ set_repd_for_rep(NSMutableArray *_reps, NSImageRep *rep, rep_data_t *new_repd)
|
|||
NSString* ext;
|
||||
rep_data_t repd;
|
||||
|
||||
ext = extension(fileName);
|
||||
ext = [fileName pathExtension];
|
||||
if (!ext)
|
||||
return NO;
|
||||
array = [[self class] imageFileTypes];
|
||||
|
|
|
@ -146,8 +146,8 @@ id gnustep_gui_nsscroller_class = nil;
|
|||
- (void)setFloatValue:(float)aFloat
|
||||
knobProportion:(float)ratio
|
||||
{
|
||||
[cell setFloatValue: aFloat];
|
||||
knob_proportion = ratio;
|
||||
[cell setFloatValue: aFloat];
|
||||
}
|
||||
|
||||
- (void)setFloatValue:(float)aFloat
|
||||
|
@ -164,6 +164,9 @@ id gnustep_gui_nsscroller_class = nil;
|
|||
//
|
||||
- (void)drawRect:(NSRect)rect
|
||||
{
|
||||
// xxx We can add some smarts here so that only the parts
|
||||
// which intersect with the rect get drawn.
|
||||
|
||||
[self drawParts];
|
||||
}
|
||||
|
||||
|
@ -206,6 +209,7 @@ id gnustep_gui_nsscroller_class = nil;
|
|||
if (!knob_dimple)
|
||||
knob_dimple = [NSImage imageNamed: @"common_Dimple"];
|
||||
[self drawKnob];
|
||||
[[self window] flushWindow];
|
||||
}
|
||||
|
||||
- (void)highlight:(BOOL)flag
|
||||
|
@ -264,10 +268,10 @@ id gnustep_gui_nsscroller_class = nil;
|
|||
|
||||
unsigned int event_mask = NSLeftMouseDownMask | NSLeftMouseUpMask |
|
||||
NSMouseMovedMask | NSLeftMouseDraggedMask | NSRightMouseDraggedMask;
|
||||
NSRect partRect = [self boundsOfScrollerPart: NSScrollerKnob];
|
||||
NSPoint point = [self convertPoint: [theEvent locationInWindow]
|
||||
fromView: nil];
|
||||
NSPoint last_point;
|
||||
NSRect knobRect = [self boundsOfScrollerPart: NSScrollerKnob];
|
||||
NSRect barRect = [self boundsOfScrollerPart: NSScrollerKnobSlot];
|
||||
float pos;
|
||||
|
||||
|
@ -286,21 +290,21 @@ id gnustep_gui_nsscroller_class = nil;
|
|||
|
||||
if (is_horizontal)
|
||||
{
|
||||
pos = (point.x - barRect.origin.x) / barRect.size.width;
|
||||
pos = (point.x - barRect.origin.x - (knobRect.size.width/2))
|
||||
/ (barRect.size.width - knobRect.size.width);
|
||||
[self setFloatValue: pos];
|
||||
[self lockFocus];
|
||||
[self drawBar];
|
||||
[self drawKnob];
|
||||
[self unlockFocus];
|
||||
[[self window] flushWindow];
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = (point.y - barRect.origin.y) / barRect.size.height;
|
||||
pos = (point.y - barRect.origin.y - (knobRect.size.height/2))
|
||||
/ (barRect.size.height - knobRect.size.height);
|
||||
[self setFloatValue: pos];
|
||||
[self lockFocus];
|
||||
[self drawBar];
|
||||
[self drawKnob];
|
||||
[self unlockFocus];
|
||||
[[self window] flushWindow];
|
||||
}
|
||||
|
||||
// Did the mouse go up?
|
||||
|
@ -316,49 +320,108 @@ id gnustep_gui_nsscroller_class = nil;
|
|||
|
||||
// Have the target perform the action
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
|
||||
// Update the display
|
||||
[self drawParts];
|
||||
[[self window] flushWindow];
|
||||
}
|
||||
|
||||
- (void)trackScrollButtons:(NSEvent *)theEvent
|
||||
{
|
||||
NSApplication *theApp = [NSApplication sharedApplication];
|
||||
BOOL mouseUp, done;
|
||||
BOOL done;
|
||||
NSEvent *e;
|
||||
unsigned int event_mask = NSLeftMouseDownMask | NSLeftMouseUpMask |
|
||||
NSMouseMovedMask | NSLeftMouseDraggedMask | NSRightMouseDraggedMask;
|
||||
NSRect partRect = [self boundsOfScrollerPart: hit_part];
|
||||
NSPoint point = [self convertPoint: [theEvent locationInWindow]
|
||||
fromView: nil];
|
||||
NSPoint last_point;
|
||||
NSScrollerArrow arrow;
|
||||
BOOL arrow_highlighted = NO;
|
||||
|
||||
// Find out which arrow button
|
||||
switch (hit_part)
|
||||
{
|
||||
case NSScrollerDecrementPage:
|
||||
case NSScrollerDecrementLine:
|
||||
arrow = NSScrollerDecrementArrow;
|
||||
break;
|
||||
case NSScrollerIncrementPage:
|
||||
case NSScrollerIncrementLine:
|
||||
default:
|
||||
arrow = NSScrollerIncrementArrow;
|
||||
break;
|
||||
}
|
||||
|
||||
// capture mouse
|
||||
[[self window] captureMouse: self];
|
||||
|
||||
// If point is in arrow then highlight it
|
||||
if ([self mouse: point inRect: partRect])
|
||||
{
|
||||
[self drawArrow: arrow highlight: YES];
|
||||
[[self window] flushWindow];
|
||||
arrow_highlighted = YES;
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
// Get next mouse events until a mouse up is obtained
|
||||
done = NO;
|
||||
e = theEvent;
|
||||
while (!done)
|
||||
{
|
||||
mouseUp = [cell trackMouse: e inRect: bounds
|
||||
ofView:self untilMouseUp:YES];
|
||||
e = [theApp currentEvent];
|
||||
last_point = point;
|
||||
e = [theApp nextEventMatchingMask:event_mask untilDate:nil
|
||||
inMode:nil dequeue:YES];
|
||||
|
||||
// If mouse went up then we are done
|
||||
if ((mouseUp) || ([e type] == NSLeftMouseUp))
|
||||
done = YES;
|
||||
point = [self convertPoint: [e locationInWindow] fromView: nil];
|
||||
|
||||
// Point is not in arrow
|
||||
if (![self mouse: point inRect: partRect])
|
||||
{
|
||||
// unhighlight arrow if highlighted
|
||||
if (arrow_highlighted)
|
||||
{
|
||||
[self drawArrow: arrow highlight: NO];
|
||||
[[self window] flushWindow];
|
||||
arrow_highlighted = NO;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NSDebugLog(@"NSScroller process another event\n");
|
||||
e = [theApp nextEventMatchingMask:event_mask untilDate:nil
|
||||
inMode:nil dequeue:YES];
|
||||
// Point is in cell
|
||||
// highlight cell if not highlighted
|
||||
if (!arrow_highlighted)
|
||||
{
|
||||
[self drawArrow: arrow highlight: YES];
|
||||
[[self window] flushWindow];
|
||||
arrow_highlighted = YES;
|
||||
}
|
||||
}
|
||||
|
||||
// Did the mouse go up?
|
||||
if ([e type] == NSLeftMouseUp)
|
||||
done = YES;
|
||||
}
|
||||
|
||||
// Release mouse
|
||||
[[self window] releaseMouse: self];
|
||||
|
||||
// If the mouse went up in the button
|
||||
if (mouseUp)
|
||||
{
|
||||
// Set a new value
|
||||
if ([self mouse: point inRect: partRect])
|
||||
{
|
||||
// unhighlight arrow
|
||||
[self drawArrow: arrow highlight: NO];
|
||||
[[self window] flushWindow];
|
||||
|
||||
// Have the target perform the action
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
|
||||
// Update the display
|
||||
[self drawParts];
|
||||
[[self window] flushWindow];
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -394,6 +457,8 @@ id gnustep_gui_nsscroller_class = nil;
|
|||
// We must have hit a real part so record it
|
||||
hit_part = area;
|
||||
|
||||
[self lockFocus];
|
||||
|
||||
// Track the knob if that's where it hit
|
||||
if ((hit_part == NSScrollerKnob) || (hit_part == NSScrollerKnobSlot))
|
||||
[self trackKnob: theEvent];
|
||||
|
@ -404,6 +469,8 @@ id gnustep_gui_nsscroller_class = nil;
|
|||
(hit_part == NSScrollerIncrementPage) ||
|
||||
(hit_part == NSScrollerIncrementLine))
|
||||
[self trackScrollButtons: theEvent];
|
||||
|
||||
[self unlockFocus];
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -87,6 +87,24 @@ static id MB_NSTEXTFIELDCELL_CLASS = nil;
|
|||
return self;
|
||||
}
|
||||
|
||||
//
|
||||
// Creating copies
|
||||
//
|
||||
- (void)setTextCursor:(NSCursor *)aCursor
|
||||
{
|
||||
text_cursor = aCursor;
|
||||
}
|
||||
|
||||
- copyWithZone:(NSZone *)zone
|
||||
{
|
||||
id c;
|
||||
|
||||
c = [super copyWithZone: zone];
|
||||
|
||||
[c setTextCursor: [NSCursor IBeamCursor]];
|
||||
return c;
|
||||
}
|
||||
|
||||
//
|
||||
// Setting User Access to Text
|
||||
//
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
background_color = [NSColor whiteColor];
|
||||
text_color = [NSColor blackColor];
|
||||
cell_font = [NSFont systemFontOfSize:12];
|
||||
draw_background = YES;
|
||||
return self;
|
||||
}
|
||||
|
||||
|
|
|
@ -259,9 +259,28 @@ NSString *NSViewFocusChangedNotification = @"NSViewFocusChangedNotification";
|
|||
|
||||
- (NSView *)ancestorSharedWithView:(NSView *)aView
|
||||
{
|
||||
NSView *v = nil;
|
||||
// Are they the same?
|
||||
if (self == aView)
|
||||
return self;
|
||||
|
||||
return v;
|
||||
// Is self a descendant of view?
|
||||
if ([self isDescendantOf: aView])
|
||||
return aView;
|
||||
|
||||
// Is view a descendant of self?
|
||||
if ([aView isDescendantOf: self])
|
||||
return self;
|
||||
|
||||
// If neither are descendants of each other
|
||||
// and either does not have a superview
|
||||
// then they cannot have a common ancestor
|
||||
if (![self superview])
|
||||
return nil;
|
||||
if (![aView superview])
|
||||
return nil;
|
||||
|
||||
// Find the common ancestor of superviews
|
||||
return [[self superview] ancestorSharedWithView: [aView superview]];
|
||||
}
|
||||
|
||||
- (BOOL)isDescendantOf:(NSView *)aView
|
||||
|
@ -734,11 +753,25 @@ NSString *NSViewFocusChangedNotification = @"NSViewFocusChangedNotification";
|
|||
//
|
||||
- (void)lockFocus
|
||||
{
|
||||
NSView *s = [self superview];
|
||||
|
||||
// lock our superview
|
||||
if (s)
|
||||
[s lockFocus];
|
||||
|
||||
// push ourselves
|
||||
[[self class] pushFocusView: self];
|
||||
}
|
||||
|
||||
- (void)unlockFocus
|
||||
{
|
||||
NSView *s = [self superview];
|
||||
|
||||
// unlock our superview
|
||||
if (s)
|
||||
[s unlockFocus];
|
||||
|
||||
// pop ourselves
|
||||
[[self class] popFocusView];
|
||||
}
|
||||
|
||||
|
|
|
@ -356,6 +356,7 @@ NSTiffRead(int imageNumber, TIFF* image, NSTiffInfo* info, char* data)
|
|||
for ( col = 0; col < newinfo->width; col++)
|
||||
for (i = 0; i < newinfo->samplesPerPixel; i++)
|
||||
{
|
||||
NSDebugLog(@"%d", *inP);
|
||||
*outP++ = *inP++;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue