This is MultiView.m in view mode; [Download] [Up]
#import "NiftyMatrix.h"
#import "MultiView.h"
#import <math.h>
@implementation MultiView
- initFrame:(const NXRect *)frm
{
[super initFrame:frm];
sel_list = [matrix getSelectedCells:nil];
num = [sel_list count];
if (num > MAX_VIEWS) num = MAX_VIEWS;
currentLay = 0;
[self initLayouts];
return self;
}
//
// deal with defaults
//
- readDefaults
{
int i = 0, j;
char *def;
const char *tmp;
char *current;
tmp = NXGetDefaultValue([NXApp appName],"MultiViews");
if (tmp) {
def = malloc(strlen(tmp) + 1);
strcpy (def,tmp);
while (def) {
current = rindex(def,':');
if (!current) {
views[i] = [self viewNamed:def];
j = [self cellNamed:def];
[matrix setSelectionFrom:j to:j anchor:j lit:YES];
break;
}
views[i] = [self viewNamed:(current+1)];
i++;
j = [self cellNamed:(current+1)];
[matrix setSelectionFrom:j to:j anchor:j lit:YES];
*current = '\0';
}
free(def);
}
tmp = NXGetDefaultValue([NXApp appName],"MultiLayout");
if (tmp)
currentLay = atoi(tmp);
printf("%s : %d\n",tmp,currentLay);
return self;
}
- writeDefaults:sender
{
int i;
const char *name;
char def[1024]; // more than we should ever need
if (num > 0) {
def[0] = '\0';
for (i = 0; i < num; i++) {
if (i)
strcat(def,":");
name = [[sel_list objectAt:i] stringValue];
strcat(def,name);
}
NXWriteDefault([NXApp appName], "MultiViews", def);
}
sprintf(def,"%d",currentLay);
NXWriteDefault([NXApp appName], "MultiLayout",def);
return self;
}
//
// whenever we receive a newWindow message, it's a good time to
// check the list and reinitialize everything
// this method is called internally everytime a new selection is made
- newWindow
{
int i, n, lays;
int x,y,w,h;
NXRect frm;
// clean up all of the old views. reset their origins
NXSetRect(&frm,0,0,50,50);
for (i = 0; i < num; i++)
[[views[i] setFrame:&frm] removeFromSuperview];
// clean up the screen... what a mess!
[self display];
// [self lockFocus];
// [self drawSelf:&frame :1];
// [self unlockFocus];
// find out what was selected, and get the appropriate views
sel_list = [matrix getSelectedCells:nil];
num = [sel_list count];
lays = lay_defs[currentLay].num;
n = MIN(lays,num);
num = n;
for (i = 0; i < n; i++) {
views[i] = [self viewFrom:[sel_list objectAt:i]];
if (NX_X(&lay_defs[currentLay].pos[i]) == 0)
x = 0;
else
x = NX_WIDTH(&frame) / NX_X(&lay_defs[currentLay].pos[i]);
if (NX_Y(&lay_defs[currentLay].pos[i]) == 0)
y = 0;
else
y = NX_HEIGHT(&frame) / NX_Y(&lay_defs[currentLay].pos[i]);
w = NX_WIDTH(&frame) / NX_WIDTH(&lay_defs[currentLay].pos[i]);
h = NX_HEIGHT(&frame) / NX_HEIGHT(&lay_defs[currentLay].pos[i]);
NXSetRect(&frm,x,y,w,h);
[[views[i] setFrame:&frm] setClipping:YES];
[self addSubview:views[i]];
// we need to make sure that they draw themselves once first
// [views[i] lockFocus];
[views[i] display];
// [views[i] unlockFocus];
}
return self;
}
//
// rather than call oneStep on every method at once,
// just call it on one, then next time, call it on the next one.
// for some reason, this seemed to improve performance
// (I'm not sure why though)
//
- oneStep
{
static int cur = 0;
[views[cur] lockFocus];
// this is necessary for some views (such as Space) to function properly
if ([views[cur] respondsTo:@selector(didLockFocus)])
[views[cur] didLockFocus];
[views[cur] oneStep];
[views[cur] unlockFocus];
cur++;
if (cur >= num)
cur = 0;
return self;
}
//
// when this is called, we know that we've just been loaded up
// so we take advantage of that fact and do a lot of initialization
//
- inspector:sender
{
char buf[MAXPATHLEN];
NXRect frm, scrollRect;
NXSize matSize, cellSize;
thinker = sender;
pub = (struct thinkerDef *)thinker;
modList = pub->moduleList;
if (!inspectorPanel)
{
//
// Time to make the matrix... time to make the matrix
//
sprintf(buf,"%s/Multi.nib",(char *)[sender moduleDirectory:"Multi"]);
[NXApp loadNibFile:buf owner:self withNames:NO];
[scrollView getFrame:&frm];
matrix = [[NiftyMatrix alloc] initFrame:&frm
mode:NX_LISTMODE
cellClass:[Cell class]
numRows:0
numCols:1];
[self fillMatrix];
[scrollView getFrame:&scrollRect];
[ScrollView getContentSize:&matSize
forFrameSize:&scrollRect.size
horizScroller:NO
vertScroller:YES
borderType:NX_BEZEL];
[matrix getCellSize:&cellSize];
cellSize.width = matSize.width;
[matrix setCellSize:&cellSize];
[matrix sizeToCells];
[matrix setAutosizeCells:YES];
[matrix setAutoscroll:YES];
[scrollView setDocView:matrix];
[[matrix superview] setAutoresizeSubviews:YES];
[matrix setAutosizing:NX_WIDTHSIZABLE];
[matrix setTarget:self];
[matrix setAction:@selector(select:)];
[matrix setDoubleAction:@selector(inspect:)];
[self readDefaults];
//
// time to make the funky layout thingie
//
// yuck... there must be a better way to initialize arrays like this
layouts[0] = lay1;
layouts[1] = lay2;
layouts[2] = lay3;
layouts[3] = lay4;
layouts[4] = lay5;
layouts[5] = lay6;
layouts[6] = lay7;
layouts[7] = lay8;
layouts[8] = lay9;
layouts[9] = lay10;
layouts[10] = lay11;
[layouts[currentLay] getFrame:&frm];
NXSetRect(&frm,0,0,NX_WIDTH(&frm),NX_HEIGHT(&frm));
[layouts[currentLay] setFrame:&frm];
[[layout addSubview:layouts[currentLay]] display];
}
return inspectorPanel;
}
//
// clean up the "multi inspector"
//
- inspectorWillBeRemoved
{
int i;
NXRect foo;
NXSetRect(&foo,0,0,0,0);
for (i = 0; i < num; i++)
[views[i] setFrame:&foo];
if (otherInspector)
[otherInspector close];
return self;
}
- setImage:image
{
int i;
for (i = 0; i < num; i++)
if ([views[i] respondsTo:@selector(setImage:)])
[views[i] setImage:image];
return self;
}
//
// helper function to -fillMatrix
//
- addCellWithString:(const char *)str at:(int)row
{
id theCell;
[matrix insertRowAt:row];
theCell = [matrix cellAt:row :0];
[theCell setStringValue:str];
return self;
}
//
// fill the matrix with the view names
///
- fillMatrix
{
int i, n, j;
n = [modList count];
for (i = j = 0; i < n; i++)
{
if (strcmp([modList nameAt: i], "Multi"))
#ifdef MULTI_LOCALIZED
[self addCellWithString:NXLocalString([modList nameAt: i], 0, 0)
#else
[self addCellWithString:[modList nameAt:i]
#endif
at:(j++)];
}
return self;
}
//
// called whenever an item in the matrix is clicked on
//
- select:sender
{
[self newWindow];
[[self window] flushWindow];
return self;
}
//
// funky layout selection interface code
//
- layoutUp:sender
{
NXRect frm;
[layouts[currentLay] removeFromSuperview];
currentLay --;
if (currentLay < 0)
currentLay = 10;
[layouts[currentLay] getFrame:&frm];
NXSetRect(&frm,0,0,NX_WIDTH(&frm),NX_HEIGHT(&frm));
[layouts[currentLay] setFrame:&frm];
[[layout addSubview:layouts[currentLay]] display];
[self newWindow];
[[self window] flushWindow];
return self;
}
- layoutDown:sender
{
NXRect frm;
[layouts[currentLay] removeFromSuperview];
currentLay ++;
if (currentLay > 10)
currentLay = 0;
[layouts[currentLay] getFrame:&frm];
NXSetRect(&frm,0,0,NX_WIDTH(&frm),NX_HEIGHT(&frm));
[layouts[currentLay] setFrame:&frm];
[[layout addSubview:layouts[currentLay]] display];
[self newWindow];
[[self window] flushWindow];
return self;
}
//
// initialize all of the layout definitions.
// this is ugly because it's all hardcoded. If I ever mess with the
// layouts in the interface, I'll also have to change this. Unfortunately,
// I didn't see a straightforward way of doing it automatically from the drawn
// layouts. Maybe I should do it the other way, and draw the layouts by hand.
// that probably makes sense if I ever do any future development on this
//
- initLayouts
{
lay_defs[0].num = 1;
[self allocLayout:0];
NXSetRect(&lay_defs[0].pos[0],0,0,1,1);
lay_defs[1].num = 2;
[self allocLayout:1];
NXSetRect(&lay_defs[1].pos[0],0,2,1,2);
NXSetRect(&lay_defs[1].pos[1],0,0,1,2);
lay_defs[2].num = 2;
[self allocLayout:2];
NXSetRect(&lay_defs[2].pos[0],0,0,2,1);
NXSetRect(&lay_defs[2].pos[1],2,0,2,1);
lay_defs[3].num = 3;
[self allocLayout:3];
NXSetRect(&lay_defs[3].pos[0],0,0,2,1);
NXSetRect(&lay_defs[3].pos[1],2,2,2,2);
NXSetRect(&lay_defs[3].pos[2],2,0,2,2);
lay_defs[4].num = 3;
[self allocLayout:4];
NXSetRect(&lay_defs[4].pos[0],0,0,2,2);
NXSetRect(&lay_defs[4].pos[1],0,2,2,2);
NXSetRect(&lay_defs[4].pos[2],2,0,2,1);
lay_defs[5].num = 3;
[self allocLayout:5];
NXSetRect(&lay_defs[5].pos[0],0,2,1,2);
NXSetRect(&lay_defs[5].pos[1],0,0,2,2);
NXSetRect(&lay_defs[5].pos[2],2,0,2,2);
lay_defs[6].num = 3;
[self allocLayout:6];
NXSetRect(&lay_defs[6].pos[0],0,0,1,2);
NXSetRect(&lay_defs[6].pos[1],0,2,2,2);
NXSetRect(&lay_defs[6].pos[2],2,2,2,2);
lay_defs[7].num = 4;
[self allocLayout:7];
NXSetRect(&lay_defs[7].pos[0],0,0,2,2);
NXSetRect(&lay_defs[7].pos[1],2,2,2,2);
NXSetRect(&lay_defs[7].pos[2],0,2,2,2);
NXSetRect(&lay_defs[7].pos[3],2,0,2,2);
lay_defs[8].num = 6;
[self allocLayout:8];
NXSetRect(&lay_defs[8].pos[0],0,0,2,3);
NXSetRect(&lay_defs[8].pos[1],2,0,2,3);
NXSetRect(&lay_defs[8].pos[2],0,3,2,3);
NXSetRect(&lay_defs[8].pos[3],2,3,2,3);
NXSetRect(&lay_defs[8].pos[4],0,1.5,2,3);
NXSetRect(&lay_defs[8].pos[5],2,1.5,2,3);
lay_defs[9].num = 6;
[self allocLayout:9];
NXSetRect(&lay_defs[9].pos[0],0,0,3,2);
NXSetRect(&lay_defs[9].pos[1],3,0,3,2);
NXSetRect(&lay_defs[9].pos[2],1.5,0,3,2);
NXSetRect(&lay_defs[9].pos[3],0,2,3,2);
NXSetRect(&lay_defs[9].pos[4],3,2,3,2);
NXSetRect(&lay_defs[9].pos[5],1.5,2,3,2);
lay_defs[10].num = 9;
[self allocLayout:10];
NXSetRect(&lay_defs[10].pos[0],0,0,3,3);
NXSetRect(&lay_defs[10].pos[1],3,3,3,3);
NXSetRect(&lay_defs[10].pos[2],1.5,1.5,3,3);
NXSetRect(&lay_defs[10].pos[3],0,3,3,3);
NXSetRect(&lay_defs[10].pos[4],3,0,3,3);
NXSetRect(&lay_defs[10].pos[5],0,1.5,3,3);
NXSetRect(&lay_defs[10].pos[6],1.5,0,3,3);
NXSetRect(&lay_defs[10].pos[7],3,1.5,3,3);
NXSetRect(&lay_defs[10].pos[8],1.5,3,3,3);
return self;
}
- allocLayout:(int)index
{
int n;
n = lay_defs[index].num;
lay_defs[index].pos = malloc(sizeof(NXRect) * n);
return self;
}
//
// BackSpace Thinker emulation code
//
- performMethodOnViews:(SEL)sel
{
int i;
for (i = 0; i < num; i++)
if ([views[i] respondsTo:sel])
[views[i] perform:sel];
return self;
}
- enteredScreenSaverMode
{
[self performMethodOnViews:@selector(enteredScreenSaverMode)];
return self;
}
- willExitScreenSaverMode
{
[self performMethodOnViews:@selector(willExitScreenSaverMode)];
return self;
}
- inspect:sender
{
id insp = nil;
NXRect frm;
if ([[self viewFrom:sender] respondsTo:@selector(inspector:)])
insp = [[self viewFrom:sender] inspector:thinker];
if (insp == nil)
insp = [thinker nullInspector];
[insp getFrame:&frm];
[otherInspector setContentView:insp];
[otherInspector makeKeyAndOrderFront:self];
[otherInspector sizeWindow:NX_WIDTH(&frm) :NX_HEIGHT(&frm)];
[[otherInspector contentView] display];
return self;
}
//
// these methods walk the list of views to match names and cells with
// the views that go with them
//
- viewFrom:sender
{
const char *name;
int i, n;
id view = nil;
name = [sender stringValue];
n = [modList count];
for (i = 0; i < n; i++)
if (!strcmp([modList nameAt: i], name))
view = [modList viewAt: i];
if (view == nil)
view = [self loadView:name];
if (view == nil)
fprintf(stderr,"returned nil: %s\n",name);
return view;
}
- viewNamed:(const char *)name
{
int i, n;
id view = nil;
n = [modList count];
for (i = 0; i < n; i++)
if (!strcmp([modList nameAt: i], name))
view = [modList viewAt: i];
if (!view)
view = [self loadView:name];
return view;
}
- objectNamed:(const char *)name
{
int i, n;
n = [modList count];
for (i = 0; i < n; i++)
if (!strcmp([modList nameAt: i], name))
return [modList objectAt: i];
return nil;
}
- (int)cellNamed:(const char *)name
{
int i, n;
n = [matrix cellCount];
for (i = 0; i < n; i++)
if (!strcmp([[matrix cellAt: i :0] stringValue], name))
return i;
return -1;
}
// this is pretty much a duplicate of - backView from ThinkMore.m
// I couldn't just call that directly because it relies on its own state
// to know what view to load
- loadView:(const char *)name
{
NXRect aFrame = {{0,0},{200,200}};
id theView = nil;
char path[MAXPATHLEN];
id myClass;
char *filenames[] = {path, NULL};
ModuleInfo *mp;
struct mach_header *header;
//if (index(name,' '))
// name = strip_spaces(name);
mp = [self objectNamed:name];
if ([mp path]) {
long ret;
while (1)
{
sprintf(path, "%s/%sView.BackO", [mp path], name);
ret = objc_loadModules(filenames, NULL, NULL, &header, NULL);
if (ret && [mp respondsTo:@selector(useNextPath)])
if ([mp useNextPath])
continue;
break;
}
if (ret)
{
NXRunAlertPanel([NXApp appName], NXLocalString("Could not dynamically load class: %sView",0,0),
NULL, NULL, NULL, name);
return nil;
}
else
{
[mp setHeader:header];
}
//at this point we must have a valid name for a loaded class
}
sprintf(path,"%sView", name);
myClass = objc_getClass(path);
// heh... god I love @defs! :-)
theView = [[myClass allocFromZone:pub->backZone] initFrame:&aFrame];
[mp setView:theView];
// fake 'em out by passing thinker instead of self
if ([theView respondsTo:@selector(inspector:)])
[theView inspector:thinker];
return theView;
}
- drawSelf:(const NXRect *)frm :(int)count
{
PSsetgray(0.0);
NXRectFillList(frm,count);
return self;
}
- (BOOL)useBufferedWindow
{
return YES;
}
- (const char *)windowTitle
{
return "MultiView";
}
- sizeTo:(NXCoord)width :(NXCoord)height
{
[super sizeTo:width :height];
[self newWindow];
return self;
}
//
// handoff methods... these all just call the equivalent in Thinker
// some of the modules depend on them
//
- commonImageInspector
{
return [thinker commonImageInspector];
}
- nullInspector
{
return [thinker nullInspector];
}
- spaceInspector
{
return [thinker spaceInspector];
}
- boinkInspector
{
return [thinker boinkInspector];
}
- (const char *)moduleDirectory:(const char *)name
{
return [thinker moduleDirectory:name];
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.