Fix bug in releasing PCButton

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/apps/projectcenter/trunk@20529 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Sergii Stoian 2005-01-08 22:17:23 +00:00
parent 27d6b344e7
commit a66f7753e3
11 changed files with 364 additions and 77 deletions

View file

@ -1,3 +1,9 @@
2005-01-09 Serg Stoyan <stoyan255@ukr.net>
* Library/PCButton.m:
(release): Added and implemented. Remove tooltips if object is
about to be dealloced.
2005-01-05 Serg Stoyan <stoyan255@ukr.net>
* Library/GNUstep.postamble: Make "ln -s" ProjectCenter to the

View file

@ -32,7 +32,7 @@
ADDITIONAL_CPPFLAGS +=
# Additional flags to pass to the Objective-C compiler
ADDITIONAL_OBJCFLAGS +=
ADDITIONAL_OBJCFLAGS +=
# Additional flags to pass to the C compiler
ADDITIONAL_CFLAGS +=

View file

@ -39,8 +39,9 @@
self = [super initWithFrame:frameRect];
[_cell setGradientType:NSGradientConvexWeak];
[self setImagePosition:NSImageOnly];
[self setFont:[NSFont systemFontOfSize: 10.0]];
[self setFont:[NSFont systemFontOfSize:10.0]];
_hasTooltips = NO;
ttTimer = nil;
ttWindow = nil;
ttTitleAttrs = [[NSMutableDictionary alloc] init];
@ -60,6 +61,12 @@
- (void)dealloc
{
#ifdef DEVELOPMENT
NSLog(@"PCButton %@: dealloc", [self stringValue]);
#endif
[[NSNotificationCenter defaultCenter] removeObserver:self];
if (_hasTooltips)
{
[self removeAllToolTips];
@ -71,6 +78,18 @@
[super dealloc];
}
- (void)release
{
// If retain count is number of tracking rects + superview retain,
// remove tracking rects. It seems that tracking rects retain this object.
if (_hasTooltips && [self retainCount] == [_tracking_rects count] + 1)
{
[self removeAllToolTips];
}
[super release];
}
// ============================================================================
// ==== Private methods
// ============================================================================
@ -87,11 +106,12 @@
{
return;
}
j = [_tracking_rects count];
for (i = 0; i < j; i++)
{
tr = [_tracking_rects objectAtIndex:i];
[self removeTrackingRect:tr->tag];
// NSLog(@"PCButton: tr: %i data: %@", tr->tag, tr->user_data);
@ -110,7 +130,6 @@
mainToolTip = tag;
}
[self removeTrackingRect:tr->tag];
RELEASE(string);
}
}
@ -272,10 +291,10 @@
}
// Set rect tracking
tag = [[self superview] addTrackingRect:aRect
owner:self
userData:data
assumeInside:NO];
tag = [self addTrackingRect:aRect
owner:self
userData:data
assumeInside:NO];
return tag;
}
@ -307,14 +326,13 @@
- (void)removeToolTip:(NSToolTipTag)tag
{
[self removeTrackingRect:tag];
// [toolTips removeObjectForKey:[NSNumber numberWithInt:tag]];
}
- (void)setToolTip:(NSString *)string
{
NSTrackingRectTag tag;
NSRect rect;
if (string == nil) // Remove old tooltip
{
if (_hasTooltips)

View file

@ -103,6 +103,18 @@
- (BOOL)becomeFirstResponder;
- (BOOL)resignFirstResponder;
// ===========================================================================
// ==== Parser and scrolling
// ===========================================================================
- (NSArray *)listOfClasses;
- (NSArray *)listOfMethodsOfClass:(NSString *)className;
- (NSArray *)listOfDefines;
- (NSArray *)listOfVars;
- (void)scrollToClassName:(NSString *)className;
- (void)scrollToMethodName:(NSString *)className;
- (void)scrollToLineNumber:(int)line;
@end
@interface PCEditor (UInterface)

View file

@ -596,5 +596,163 @@
return YES;
}
// ===========================================================================
// ==== Parser and scrolling
// ===========================================================================
- (NSString *)classNameFromString:(NSString *)string
{
NSString *className = nil;
NSMutableArray *lineComps = nil;
// @implementation ClassName (Category)
//
// @implementation ClassName(Category)
// @implementation ClassName( Category)
// @implementation ClassName(Category )
//
// @implementation ClassName ( Category )
// @implementation ClassName (Category )
// @implementation ClassName ( Category)
lineComps = [[string componentsSeparatedByString:@" "] mutableCopy];
if ([lineComps count] > 2)
// && [[[lineComps objectAtIndex:2] substringWithRange:NSMakeRange(0,1)] isEqualToString:@"("])
{
[lineComps removeObjectAtIndex:0];
className = [lineComps componentsJoinedByString:@""];
RELEASE(lineComps);
return [NSString stringWithFormat:@"@%@", className];
}
else
{
return [NSString stringWithFormat:@"@%@", [lineComps objectAtIndex:1]];
}
return nil;
}
- (NSString *)methodNameFromString:(NSString *)string
{
NSString *methodName = nil;
return methodName;
}
- (NSMutableArray *)linesWithKeyword:(NSString *)keyword atBOL:(BOOL)yn
{
NSMutableArray *lines = [[NSMutableArray alloc] init];
NSString *text = [_storage string];
NSRange range = {0, [text length]};
NSRange subRange = {0, 0};
NSRange lineRange = {0, 0};
NSString *tmpStr = nil;
NSString *lineString = nil;
while (range.location < [text length])
{
subRange = [text rangeOfString:keyword
options:NSLiteralSearch
range:range];
NSLog(@"subRange: {%i, %i}", subRange.location, subRange.length);
if (subRange.location == NSNotFound)
{
break;
}
// Set range for next search
range.location = subRange.location + subRange.length;
range.length = [text length] - range.location;
NSLog(@"range: {%i, %i}", range.location, range.length);
// If keyword is located not at the beginning of line then skip it.
if (yn)
{
tmpStr = [text substringWithRange:NSMakeRange(subRange.location-1,1)];
if (![tmpStr isEqualToString:@"\n"])
{
NSLog(@"CONTINUE %i %i", range.location, range.length);
continue;
}
}
// Get line range where @implementation is located
lineRange = [text lineRangeForRange:subRange];
lineString = [text substringWithRange:lineRange];
NSLog(@"0. line range: {%i, %i}", lineRange.location, lineRange.length);
[lines addObject:lineString];
}
return AUTORELEASE(lines);
}
- (NSArray *)listOfClasses
{
NSMutableArray *classesArray = [[NSMutableArray alloc] init];
NSMutableArray *linesArray = nil;
NSString *lineString = nil;
int i;
NSLog(@"Start searching for class implementations...");
// Get lines with keywords
if ([[[_path lastPathComponent] pathExtension] isEqualToString:@"m"])
{
linesArray = [self linesWithKeyword:@"@implementation" atBOL:YES];
}
else if ([[[_path lastPathComponent] pathExtension] isEqualToString:@"h"])
{
linesArray = [self linesWithKeyword:@"@interface" atBOL:YES];
}
// Get class names
for (i = 0; i < [linesArray count]; i++)
{
lineString = [linesArray objectAtIndex:i];
[classesArray addObject:[self classNameFromString:lineString]];
}
return AUTORELEASE((NSArray*)classesArray);
}
- (NSArray *)listOfMethodsOfClass:(NSString *)className
{
NSMutableArray *methodsArray = [[NSMutableArray alloc] init];
return AUTORELEASE((NSArray*)methodsArray);
}
- (NSArray *)listOfDefines
{
NSMutableArray *definesArray = [[NSMutableArray alloc] init];
return AUTORELEASE((NSArray*)definesArray);
}
- (NSArray *)listOfVars
{
NSMutableArray *varsArray = [[NSMutableArray alloc] init];
return AUTORELEASE((NSArray*)varsArray);
}
//--- Scrolling
- (void)scrollToClassName:(NSString *)className
{
}
- (void)scrollToMethodName:(NSString *)className
{
}
- (void)scrollToLineNumber:(int)line
{
}
@end

View file

@ -134,6 +134,7 @@ extern NSString *PCProjectDictDidSaveNotification;
- (NSArray *)localizableKeys;
- (BOOL)isEditableCategory:(NSString *)category;
- (BOOL)isEditableFile:(NSString *)filePath;
- (NSArray *)fileTypesForCategoryKey:(NSString *)key;
- (NSString *)categoryKeyForFileType:(NSString *)type;
- (NSString *)dirForCategoryKey:(NSString *)key;

View file

@ -512,6 +512,28 @@ NSString
return NO;
}
- (BOOL)isEditableFile:(NSString *)filePath
{
NSString *key = [self keyForCategory:[projectBrowser nameOfSelectedCategory]];
NSString *extension = [filePath pathExtension];
if ([key isEqualToString:PCSupportingFiles]
|| [key isEqualToString:PCDocuFiles])
{
return YES;
}
if ([extension isEqualToString:@"m"]
|| [extension isEqualToString:@"h"]
|| [extension isEqualToString:@"c"]
|| [extension isEqualToString:@"plist"])
{
return YES;
}
return NO;
}
- (NSArray *)fileTypesForCategoryKey:(NSString *)key
{
if ([key isEqualToString:PCClasses])
@ -1355,6 +1377,11 @@ NSString
return [_subproject contentAtCategoryPath:spCategoryPath];
}
else if ([[[categoryPath lastPathComponent] pathExtension] isEqualToString:@"m"]
|| [[[categoryPath lastPathComponent] pathExtension] isEqualToString:@"h"])
{ // ".m" file
return [[projectEditor activeEditor] listOfClasses];
}
return [projectDict objectForKey:key];
}
@ -1370,16 +1397,31 @@ NSString
}
listEntry = [[categoryPath componentsSeparatedByString:@"/"] lastObject];
// Categories
if ([rootCategories containsObject:listEntry])
{
return YES;
}
// Subprojects
if ([[projectDict objectForKey:PCSubprojects] containsObject:listEntry]
&& [[projectBrowser nameOfSelectedCategory] isEqualToString:@"Subprojects"])
{
return YES;
}
// Class and header files
/* if ([[listEntry pathExtension] isEqualToString:@"m"]
|| [[listEntry pathExtension] isEqualToString:@"h"])
{
return YES;
}*/
// TODO: Libraries
// if ([[projectBrowser nameOfSelectedCategory] isEqualToString:@"Libraries"])
// {
// }
return NO;
}

View file

@ -289,7 +289,21 @@ NSString *PCBrowserDidSetPathNotification = @"PCBrowserDidSetPathNotification";
PCProject *p = [[project projectManager] activeProject];
NSString *catKey = [p keyForCategory:[self nameOfSelectedCategory]];
NSArray *array = [[p projectDict] objectForKey:catKey];
NSString *path = [self path];
NSString *tmp = nil;
// Determine last column with files (removing classes and methods from path)
tmp = [[path lastPathComponent] substringWithRange:NSMakeRange(0,1)];
while ([tmp isEqualToString:@"@"] // classes
|| [tmp isEqualToString:@"+"] // factory methods
|| [tmp isEqualToString:@"-"]) // instance methods
{
path = [path stringByDeletingLastPathComponent];
tmp = [[path lastPathComponent] substringWithRange:NSMakeRange(0,1)];
}
NSLog(@"PCBrowser set path: %@", path);
[self setPath:[path stringByDeletingLastPathComponent]];
[self reloadLastColumnAndNotify:NO];
[browser selectRow:[array indexOfObject:file] inColumn:[browser lastColumn]];
@ -306,13 +320,13 @@ NSString *PCBrowserDidSetPathNotification = @"PCBrowserDidSetPathNotification";
- (void)click:(id)sender
{
NSUserDefaults *ud = nil;
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
NSFileManager *fm = [NSFileManager defaultManager];
NSString *category = nil;
NSString *fileName = nil;
NSString *filePath = nil;
NSString *key = nil;
PCProject *activeProject = nil;
NSFileManager *fm = [NSFileManager defaultManager];
BOOL isDir;
if (sender != browser)
@ -320,28 +334,33 @@ NSString *PCBrowserDidSetPathNotification = @"PCBrowserDidSetPathNotification";
return;
}
if ([[sender selectedCell] isLeaf] && [[self selectedFiles] count] == 1)
category = [self nameOfSelectedCategory];
activeProject = [[project projectManager] activeProject];
// [[sender selectedCell] isLeaf]
if ([activeProject isEditableCategory:category]
&& [[self selectedFiles] count] == 1)
{
ud = [NSUserDefaults standardUserDefaults];
category = [self nameOfSelectedCategory];
fileName = [[sender selectedCell] stringValue];
activeProject = [[project projectManager] activeProject];
key = [activeProject keyForCategory:category];
filePath = [activeProject dirForCategoryKey:key];
filePath = [filePath stringByAppendingPathComponent:fileName];
/* PCLogInfo(self, @"[click] category: %@ filePath: %@",
category, filePath);*/
if ([activeProject isEditableCategory:category]
&& [fm fileExistsAtPath:filePath isDirectory:&isDir] && !isDir)
if ([fm fileExistsAtPath:filePath isDirectory:&isDir] && !isDir
&& [activeProject isEditableFile:filePath])
{
if (![[ud objectForKey:SeparateEditor] isEqualToString:@"YES"])
{
NSString *path = [self path];
[[project projectEditor] editorForFile:filePath
categoryPath:[browser path]
windowed:NO];
[self reloadLastColumnAndNotify:NO];
[self setPath:path];
}
}
}

View file

@ -64,6 +64,7 @@
*/
buildButton = [[PCButton alloc] initWithFrame: NSMakeRect(0,271,43,43)];
[buildButton setToolTip: @"Build"];
[buildButton setTitle: @"Make"];
[buildButton setImage: IMAGE(@"Build")];
[buildButton setAlternateImage: IMAGE(@"Stop")];
[buildButton setTarget: self];
@ -75,6 +76,7 @@
cleanButton = [[PCButton alloc] initWithFrame: NSMakeRect(44,271,43,43)];
[cleanButton setToolTip: @"Clean"];
[cleanButton setTitle: @"Make-Clean"];
[cleanButton setImage: IMAGE(@"Clean")];
[cleanButton setAlternateImage: IMAGE(@"Stop")];
[cleanButton setTarget: self];
@ -86,6 +88,7 @@
installButton = [[PCButton alloc] initWithFrame: NSMakeRect(88,271,43,43)];
[installButton setToolTip: @"Install"];
[installButton setTitle: @"Make-Install"];
[installButton setImage: IMAGE(@"Install")];
[installButton setAlternateImage: IMAGE(@"Stop")];
[installButton setTarget: self];
@ -97,6 +100,7 @@
optionsButton = [[PCButton alloc] initWithFrame: NSMakeRect(132,271,43,43)];
[optionsButton setToolTip: @"Options"];
[optionsButton setTitle: @"Make-Options"];
[optionsButton setImage: IMAGE(@"Options")];
[optionsButton setTarget: self];
[optionsButton setAction: @selector(showOptionsPanel:)];

View file

@ -161,6 +161,12 @@ NSString *PCEditorDidResignActiveNotification =
componentView = nil;
editorsDict = [[NSMutableDictionary alloc] init];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(editorDidOpen:)
name:PCEditorDidOpenNotification
object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(editorDidClose:)
@ -461,9 +467,22 @@ NSString *PCEditorDidResignActiveNotification =
// ==== Notifications
// ===========================================================================
- (void)editorDidOpen:(NSNotification *)aNotif
{
/* PCEditor *editor = [aNotif object];
PCProjectBrowser *browser = [project projectBrowser];
NSString *path = [browser path];
// Active editor is set after PCEditorDidBecomeActiveNotification will be
// sent, but we should do it here for loading list of classes into browser.
[self setActiveEditor:editor];
[browser reloadLastColumnAndNotify:NO];
[browser setPath:path];*/
}
- (void)editorDidClose:(NSNotification *)aNotif
{
PCEditor *editor = [aNotif object];
PCEditor *editor = [aNotif object];
// It is not our editor
if ([editor projectEditor] != self)
@ -484,10 +503,13 @@ NSString *PCEditorDidResignActiveNotification =
}
else
{
PCProjectBrowser *browser = [project projectBrowser];
NSString *path = [browser path];
[componentView setContentView:scrollView];
[[project projectWindow] makeFirstResponder:scrollView];
[[project projectBrowser] reloadLastColumnAndNotify:YES];
[browser setPath:[path stringByDeletingLastPathComponent]];
}
}

View file

@ -99,30 +99,32 @@
[toolbarView setTitlePosition:NSNoTitle];
[toolbarView setBorderType:NSNoBorder];
[toolbarView setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin];
[toolbarView setContentViewMargins: NSMakeSize(0.0,0.0)];
[toolbarView setContentViewMargins:NSMakeSize(0.0,0.0)];
[_c_view addSubview:toolbarView];
RELEASE(toolbarView);
buildButton = [[PCButton alloc] initWithFrame: NSMakeRect(0,5,43,43)];
buildButton = [[PCButton alloc] initWithFrame:NSMakeRect(0,5,43,43)];
[buildButton setRefusesFirstResponder:YES];
[buildButton setToolTip: @"Build"];
[buildButton setImage: IMAGE(@"Build")];
[buildButton setTarget: self];
[buildButton setAction: @selector(showProjectBuild:)];
[buildButton setAutoresizingMask: (NSViewMaxXMargin | NSViewMinYMargin)];
[buildButton setButtonType: NSMomentaryPushButton];
[toolbarView addSubview: buildButton];
RELEASE (buildButton);
[buildButton setToolTip:@"Build"];
[buildButton setTitle:@"Build"];
[buildButton setImage:IMAGE(@"Build")];
[buildButton setTarget:self];
[buildButton setAction:@selector(showProjectBuild:)];
[buildButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)];
[buildButton setButtonType:NSMomentaryPushButton];
[toolbarView addSubview:buildButton];
RELEASE(buildButton);
launchButton = [[PCButton alloc] initWithFrame: NSMakeRect(44,5,43,43)];
launchButton = [[PCButton alloc] initWithFrame:NSMakeRect(44,5,43,43)];
[launchButton setRefusesFirstResponder:YES];
[launchButton setToolTip: @"Launch/Debug"];
[launchButton setImage: IMAGE(@"Run")];
[launchButton setTarget: self];
[launchButton setAction: @selector(showProjectLaunch:)];
[launchButton setAutoresizingMask: (NSViewMaxXMargin | NSViewMinYMargin)];
[launchButton setButtonType: NSMomentaryPushButton];
[toolbarView addSubview: launchButton];
[launchButton setToolTip:@"Launch/Debug"];
[launchButton setTitle:@"Launch/Debug"];
[launchButton setImage:IMAGE(@"Run")];
[launchButton setTarget:self];
[launchButton setAction:@selector(showProjectLaunch:)];
[launchButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)];
[launchButton setButtonType:NSMomentaryPushButton];
[toolbarView addSubview:launchButton];
RELEASE (launchButton);
if (![project isExecutable])
@ -130,56 +132,59 @@
[launchButton setEnabled:NO];
}
loadedFilesButton = [[PCButton alloc] initWithFrame: NSMakeRect(88,5,43,43)];
loadedFilesButton = [[PCButton alloc] initWithFrame:NSMakeRect(88,5,43,43)];
[loadedFilesButton setRefusesFirstResponder:YES];
[loadedFilesButton setToolTip: @"Loaded Files"];
[loadedFilesButton setImage: IMAGE(@"Files")];
[loadedFilesButton setTarget: self];
[loadedFilesButton setAction: @selector(showProjectLoadedFiles:)];
[loadedFilesButton setToolTip:@"Loaded Files"];
[loadedFilesButton setTitle:@"Loaded Files"];
[loadedFilesButton setImage:IMAGE(@"Files")];
[loadedFilesButton setTarget:self];
[loadedFilesButton setAction:@selector(showProjectLoadedFiles:)];
[loadedFilesButton
setAutoresizingMask: (NSViewMaxXMargin | NSViewMinYMargin)];
[loadedFilesButton setButtonType: NSMomentaryPushButton];
[toolbarView addSubview: loadedFilesButton];
RELEASE (loadedFilesButton);
setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)];
[loadedFilesButton setButtonType:NSMomentaryPushButton];
[toolbarView addSubview:loadedFilesButton];
RELEASE(loadedFilesButton);
if ([self hasLoadedFilesView])
{
[loadedFilesButton setEnabled:NO];
}
findButton = [[PCButton alloc] initWithFrame: NSMakeRect(132,5,43,43)];
findButton = [[PCButton alloc] initWithFrame:NSMakeRect(132,5,43,43)];
[findButton setRefusesFirstResponder:YES];
[findButton setToolTip: @"Find"];
[findButton setImage: IMAGE(@"Find")];
[findButton setTarget: project];
[findButton setAction: @selector(showFindView:)];
[findButton setAutoresizingMask: (NSViewMaxXMargin | NSViewMinYMargin)];
[findButton setButtonType: NSMomentaryPushButton];
[toolbarView addSubview: findButton];
RELEASE (findButton);
[findButton setToolTip:@"Find"];
[findButton setTitle:@"Find"];
[findButton setImage:IMAGE(@"Find")];
[findButton setTarget:project];
[findButton setAction:@selector(showFindView:)];
[findButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)];
[findButton setButtonType:NSMomentaryPushButton];
[toolbarView addSubview:findButton];
RELEASE(findButton);
inspectorButton = [[PCButton alloc] initWithFrame: NSMakeRect(176,5,43,43)];
inspectorButton = [[PCButton alloc] initWithFrame:NSMakeRect(176,5,43,43)];
[inspectorButton setRefusesFirstResponder:YES];
[inspectorButton setToolTip: @"Inspector"];
[inspectorButton setImage: IMAGE(@"Inspector")];
[inspectorButton setTarget: [project projectManager]];
[inspectorButton setAction: @selector(showProjectInspector:)];
[inspectorButton setToolTip:@"Inspector"];
[inspectorButton setTitle:@"Inspector"];
[inspectorButton setImage:IMAGE(@"Inspector")];
[inspectorButton setTarget:[project projectManager]];
[inspectorButton setAction:@selector(showProjectInspector:)];
[inspectorButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)];
[inspectorButton setButtonType: NSMomentaryPushButton];
[toolbarView addSubview: inspectorButton];
RELEASE (inspectorButton);
[inspectorButton setButtonType:NSMomentaryPushButton];
[toolbarView addSubview:inspectorButton];
RELEASE(inspectorButton);
/*
* File icon and title
*/
fileIcon = [[NSImageView alloc] initWithFrame: NSMakeRect (496,0,48,48)];
fileIcon = [[NSImageView alloc] initWithFrame:NSMakeRect (496,0,48,48)];
[fileIcon setRefusesFirstResponder:YES];
[fileIcon setEditable:NO];
[fileIcon setAutoresizingMask: (NSViewMinXMargin | NSViewMinYMargin)];
[fileIcon setImage: IMAGE (@"projectSuitcase")];
[toolbarView addSubview: fileIcon];
RELEASE (fileIcon);
[fileIcon setAutoresizingMask:(NSViewMinXMargin | NSViewMinYMargin)];
[fileIcon setImage:IMAGE(@"projectSuitcase")];
[toolbarView addSubview:fileIcon];
RELEASE(fileIcon);
fileIconTitle = [[NSTextField alloc]
initWithFrame: NSMakeRect (308,4,180,21)];
@ -191,9 +196,9 @@
[fileIconTitle setDrawsBackground: NO];
[fileIconTitle setAlignment:NSRightTextAlignment];
[fileIconTitle setBezeled:NO];
[toolbarView addSubview: fileIconTitle];
RELEASE (fileIconTitle);
[toolbarView addSubview:fileIconTitle];
RELEASE(fileIconTitle);
/*
* Hosrizontal split view
*/
@ -203,7 +208,7 @@
rect.origin.x += 8;
rect.origin.y = -2;
h_split = [[PCSplitView alloc] initWithFrame:rect];
[h_split setAutoresizingMask: (NSViewWidthSizable | NSViewHeightSizable)];
[h_split setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
/*
* Vertical split view