/*
* This file is part of rasdaman community.
*
* Rasdaman community is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Rasdaman community is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with rasdaman community. If not, see .
*
* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
rasdaman GmbH.
*
* For more information please see
* or contact Peter Baumann via .
/
/**
* PURPOSE:
*
* Base class for all object viewers (rviewImage, rviewChart, rviewTable
* and rviewSound). Provides a frame with standard control widgets and
* menus, functions for parsing/advancing the projection string and
* initializing protected variables according to the MDD object that will
* be displayed.
*
* COMMENTS:
* None
*/
// Standard wxWindows preamble.
#ifdef __GNUG__
#pragma implementation
#endif
// changed in wxWindows 2.4.2:
//#include "wx_prec.h"
#include
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include
#endif
#include
#include
#include
#ifdef EARLY_TEMPLATE
#define __EXECUTABLE__
#endif
#include "raslib/rmdebug.hh"
#include "rviewTypes.hh"
#include "labelManager.hh"
#include "rviewUtils.hh"
#include "rviewDisplay.hh"
#include "rviewPrefs.hh"
#include "rviewApp.hh"
/*
* Need a slightly more sophisticated panel than the default one
*/
class rviewDisplayPanel : public wxPanel
{
public:
rviewDisplayPanel(rviewDisplay *parent, int posx, int posy, int width, int height);
virtual void OnEvent(wxMouseEvent &mevt);
virtual void OnItemEvent(wxItem *item, wxMouseEvent &mevt);
};
rviewDisplayPanel::rviewDisplayPanel(rviewDisplay *parent, int posx, int posy, int width, int height) :
wxPanel((wxWindow*)parent, posx, posy, width, height)
{
}
void rviewDisplayPanel::OnEvent(wxMouseEvent &mevt)
{
rviewDisplay *disp = (rviewDisplay*)(GetParent());
disp->childMouseEvent(this, mevt);
wxPanel::OnEvent(mevt);
}
void rviewDisplayPanel::OnItemEvent(wxItem *item, wxMouseEvent &mevt)
{
rviewDisplay *disp = (rviewDisplay*)(GetParent());
disp->childMouseEvent(item, mevt);
wxPanel::OnItemEvent(item, mevt);
}
/*
* Constants
*/
// window dimensions
const int rviewDisplay::display_width = 300;
const int rviewDisplay::display_height = 400;
const int rviewDisplay::display_cnvborder = 10;
const int rviewDisplay::display_border = 8;
const int rviewDisplay::display_scrstep = 8;
const int rviewDisplay::display_pgstep = 8;
const int rviewDisplay::display_cheight = 60;
const int rviewDisplay::display_pjheight = 50;
const int rviewDisplay::display_pjwidth = 100;
const int rviewDisplay::display_pbwidth = 40;
const int rviewDisplay::display_pbheight = 30;
const int rviewDisplay::display_minwidth = 4*(rviewDisplay::display_pbwidth + rviewDisplay::display_border);
// flags
const int rviewDisplay::display_flag_standalone = 1;
const int rviewDisplay::display_flag_update = 2;
// others
const int rviewDisplay::fixedNumberOfMenus = 2;
const unsigned int rviewDisplay::viewBuffSize = 1024;
const char *rviewDisplay::viewFileExtension = "*.rvw";
const char *rviewDisplay::view_HeaderLine = "# rView viewer snapshot";
const char *rviewDisplay::view_ViewerType = "viewerName";
const char *rviewDisplay::view_ProjString = "projString";
const char *rviewDisplay::view_WindowSize = "windowSize";
/*
* rviewDisplay members
*/
// The global display counter.
int rviewDisplay::displayCounter=0;
rviewDisplay::rviewDisplay(mdd_frame *mf, int es, unsigned int flags) : rviewFrame(NULL, "", 0, 0, display_width, display_height)
{
int x, y, pw;
r_Object *mo;
char buffer[STRINGSIZE];
if ((flags & display_flag_standalone & display_flag_update) != 0)
RMDBGENTER(3, RMDebug::module_applications, "rviewDisplay", "rviewDisplay() [UA]")
else if ((flags & display_flag_standalone) != 0)
RMDBGENTER(3, RMDebug::module_applications, "rviewDisplay", "rviewDisplay() [A]")
else if ((flags & display_flag_update) != 0)
RMDBGENTER(3, RMDebug::module_applications, "rviewDisplay", "rviewDisplay() [U]")
// Override by derived classes if an error occurs.
// Can't use virtual functions in constructors!
objectInitializedOK = TRUE;
closeViewerCalled = FALSE;
displayFlags = flags;
mddObj = mf->mdd; extraSpace = es;
totalCtrlHeight = display_cheight + extraSpace;
rootTitle[0] = '\0';
displayOperation = FALSE; // used to avoid reentrancy on resize
minViewX = 0; minViewY = 0; dimMode = -1;
// Copy the current (global) display counter and increment it, thus creating a unique
// ID for each display window.
displayID = displayCounter++;
qwindowID = -1; // no query window
projString[0] = '\0';
baseSize = (int)(mddObj->get_type_length());
// Determine base type
mo = (r_Object*)(&(*mddObj));
baseType = rviewGetBasetype(mo);
interv = mddObj->spatial_domain();
dimMDD = interv.dimension();
mBar = NULL;
ctrlPanel = NULL; project = NULL;
GetClientSize(&x, &y);
ctrlPanel = new rviewDisplayPanel(this, 0, 0, x, totalCtrlHeight);
ctrlPanel->SetLabelPosition(wxVERTICAL);
x -= 2*display_border; pw = x;
if (pw > display_pjwidth) pw = display_pjwidth;
project = new rviewText(ctrlPanel);
projBut = new rviewButton(ctrlPanel);
projMinus = new rviewButton(ctrlPanel, "-");
advance = new rviewText(ctrlPanel);
projPlus = new rviewButton(ctrlPanel, "+");
typeMsg = new wxMessage(ctrlPanel, "");
// Have to duplicate this code bit.
sprintf(buffer, "%s: %s", lman->lookup("textBaseType"), rviewBaseTypes[baseType]);
typeMsg->SetLabel(buffer);
frameWidth=-1;
frameWidth=-1;
RMDBGEXIT(3, RMDebug::module_applications, "rviewDisplay", "rviewDisplay()");
}
rviewDisplay::~rviewDisplay(void)
{
if((displayFlags & display_flag_standalone & display_flag_update) != 0)
RMDBGEXIT(3, RMDebug::module_applications, "rviewDisplay", "~rviewDisplay() [UA]")
else if ((displayFlags & display_flag_standalone) != 0)
RMDBGEXIT(3, RMDebug::module_applications, "rviewDisplay", "~rviewDisplay() [A]")
else if ((displayFlags & display_flag_update) != 0)
RMDBGEXIT(3, RMDebug::module_applications, "rviewDisplay", "~rviewDisplay() [U]")
// Update display dying, notify other frames (-> query windows)
if ((displayFlags & display_flag_update) != 0)
{
user_event ue;
ue.type = usr_update_closed;
ue.data = (void*)(&mddObj);
if (frameManager != NULL)
frameManager->broadcastUserEvent(ue);
}
// If standalone free all memory.
if ((displayFlags & display_flag_standalone) != 0)
{
mddObj.destroy();
}
}
// notify the parent window that a viewer has been closed;
// called from viewer destructor.
void rviewDisplay::closeViewer(void)
{
RMDBGONCE(3, RMDebug::module_applications, "rviewDisplay", "closeViewer()");
if (!closeViewerCalled)
{
if (parentFrame != NULL)
{
mdd_frame mf;
user_event ue;
mf.flags = getViewerType(); mf.mdd = mddObj;
ue.type = usr_viewer_closed; ue.data = (void*)(&mf);
parentFrame->userEvent(ue);
}
closeViewerCalled = TRUE;
}
}
const char *rviewDisplay::getFrameName(void) const
{
return "rviewDisplay";
}
rviewFrameType rviewDisplay::getFrameType(void) const
{
return rviewFrameTypeDisplay;
}
const r_Minterval &rviewDisplay::getVirtualDomain(void) const
{
return interv;
}
// Must concentrate all functionality relying on virtual functions here rather than
// the constructor
int rviewDisplay::openViewer(void)
{
int w, h, x, y;
char buffer[STRINGSIZE];
RMDBGONCE(3, RMDebug::module_applications, "rviewDisplay", "openViewer()");
mBar = new wxMenuBar;
wxMenu *menu = new wxMenu;
menu->Append(MENU_DISP_DATA_INSERT, "");
menu->Append(MENU_DISP_DATA_INSERTPRO, "");
menu->Append(MENU_DISP_DATA_SAVE, "");
fileMenuInitHook(menu);
menu->Append(MENU_DISP_DATA_CLOSE, "");
sprintf(buffer, "&%s", lman->lookup("menDispData"));
mBar->Append(menu, buffer);
menu = new wxMenu;
menu->Append(MENU_DISP_VIEW_SAVE, "");
menu->Append(MENU_DISP_VIEW_LOAD, "");
viewMenuInitHook(menu);
sprintf(buffer, "&%s", lman->lookup("menDispView"));
mBar->Append(menu, buffer);
menuBarInitHook();
GetSize(&w, &h);
//lastWidth = w; lastHeight = h;
GetClientSize(&x, &y);
mbarHeight = h - y;
//cout << "mbar height " << mbarHeight << endl;
SetMenuBar(mBar);
newDBState(rmanClientApp::theApp()->ReadDBState());
return 0;
}
void rviewDisplay::setModeDimension(int dim)
{
bool enable;
char adbuff[4];
dimMode = dim; sprintf(adbuff, "%d", dim);
advance->SetValue(adbuff);
enable = (dimMDD > dimMode);
projPlus->Enable(enable); projMinus->Enable(enable); advance->Enable(enable);
}
void rviewDisplay::label(void)
{
char btbuf[STRINGSIZE];
mBar->SetLabel(MENU_DISP_DATA_INSERT, lman->lookup("menDispDataIsrt"));
mBar->SetLabel(MENU_DISP_DATA_INSERTPRO, lman->lookup("menDispDataIsrtPro"));
mBar->SetLabel(MENU_DISP_DATA_SAVE, lman->lookup("menDispDataSave"));
mBar->SetLabel(MENU_DISP_DATA_CLOSE, lman->lookup("menDispDataClose"));
mBar->SetLabelTop(0, lman->lookup("menDispData"));
mBar->SetLabel(MENU_DISP_VIEW_SAVE, lman->lookup("menDispViewSave"));
mBar->SetLabel(MENU_DISP_VIEW_LOAD, lman->lookup("menDispViewLoad"));
mBar->SetLabelTop(1, lman->lookup("menDispView"));
project->SetLabel(lman->lookup("textProjString"));
projBut->SetLabel(lman->lookup("textOK"));
sprintf(btbuf, "%s: %s", lman->lookup("textBaseType"), rviewBaseTypes[baseType]);
typeMsg->SetLabel(btbuf);
}
void rviewDisplay::newDBState(bool dbstate)
{
mBar->Enable(MENU_DISP_DATA_INSERT, dbstate);
mBar->Enable(MENU_DISP_DATA_INSERTPRO, dbstate);
}
int rviewDisplay::process(wxObject &obj, wxEvent &evt)
{
int type = evt.GetEventType();
if (((&obj == (wxObject*)project) && (type == wxEVENT_TYPE_TEXT_ENTER_COMMAND)) || ((&obj == (wxObject*)projBut) && (type == wxEVENT_TYPE_BUTTON_COMMAND)))
{
strcpy(projString, project->GetValue());
newProjection();
return 1;
}
if (((&obj == (wxObject*)projPlus) || (&obj == (wxObject*)projMinus)) && (type == wxEVENT_TYPE_BUTTON_COMMAND))
{
if (advanceProjection((&obj == (wxObject*)projPlus) ? 1 : -1) != 0)
{
strcpy(projString, project->GetValue());
newProjection();
return 1;
}
}
return 0;
}
void rviewDisplay::OnSize(int w, int h)
{
int x, y, pw, pos, minw, minh;
float tw, th;
RMDBGONCE(3, RMDebug::module_applications, "rviewDisplay", "OnSize(" << w << ", " << h << " )");
if (!displayOperation)
{
project->GetTextExtent((const char*)(lman->lookup("textProjString")), &tw, &th, NULL, NULL, wxSWISS_FONT, FALSE);
minw = display_minwidth + ((int)tw);
if (minw < minViewX) minw = minViewX;
minh = totalCtrlHeight + minViewY + mbarHeight;
if ((w < minw) || (h < minh))
{
// Avoid infinite loops / reentrancy
displayOperation = TRUE;
if (w < minw) w = minw;
if (h < minh) h = minh;
//cout << "resize display frame to " << w << ", " << h << " / min " << minViewX << ", " << minViewY << endl;
SetSize(-1, -1, w, h);
displayOperation = FALSE;
}
}
GetClientSize(&x, &y);
ctrlPanel->SetSize(0, 0, x, totalCtrlHeight);
pos = x - 3*display_pbwidth - display_border;
pw = pos - 3*display_border - display_pbwidth;
x -= 2*display_border;
project->SetSize(display_border, display_border, pw, display_pjheight);
y = display_border + (display_pjheight - display_pbheight);
projBut->SetSize(2*display_border + pw, y, display_pbwidth, display_pbheight);
projMinus->SetSize(pos, y, display_pbwidth, display_pbheight);
advance->SetSize(pos + display_pbwidth, y - display_border, display_pbwidth, 4*display_pbheight/3);
projPlus->SetSize(pos + 2*display_pbwidth, y, display_pbwidth, display_pbheight);
// Default label font seems to be swiss font. Changing it doesn't appear to
// have any effect.
typeMsg->GetTextExtent((const char*)(typeMsg->GetLabel()), &tw, &th, NULL, NULL, wxSWISS_FONT, FALSE);
typeMsg->SetSize(display_border + x - tw, display_border, tw, th);
}
void rviewDisplay::OnMenuCommand(int id)
{
switch (id)
{
case MENU_DISP_DATA_INSERT:
rmanClientApp::theApp()->insertMDD(mddObj);
break;
case MENU_DISP_DATA_INSERTPRO:
{
r_Minterval useInterv(dimMDD);
int i;
for (i=0; iinsertMDD(mddObj, NULL, &useInterv);
}
break;
case MENU_DISP_DATA_SAVE:
{
char *prefDir = (char*)(prefs->filePath.ptr());
char *s = wxFileSelector(lman->lookup("saveData"), (::wxDirExists(prefDir)) ? prefDir : NULL, NULL, NULL, "*", 0, this);
if (s)
{
FILE *fp;
size_t dataSize = (size_t)baseSize;
int i;
prefs->filePath = ::wxPathOnly(s);
for (i=0; ilookup("errorFileOpen"), s);
rviewErrorbox::reportError(buffer, rviewDisplay::getFrameName(), "OnMenuCommand");
}
else
{
if (fwrite(mddObj->get_array(), 1, dataSize, fp) != dataSize)
{
char buffer[STRINGSIZE];
sprintf(buffer, "%s %s", lman->lookup("errorFileWrite"), s);
rviewErrorbox::reportError(buffer, rviewDisplay::getFrameName(), "OnMenuCommand");
}
fclose(fp);
}
}
}
break;
case MENU_DISP_DATA_CLOSE:
prepareToDie(); this->Close(TRUE);
break;
case MENU_DISP_VIEW_SAVE:
doSaveView();
break;
case MENU_DISP_VIEW_LOAD:
doLoadView();
break;
default: break;
}
}
int rviewDisplay::userEvent(const user_event &ue)
{
if (ue.type == usr_mdd_dying)
{
if (*((r_Ref*)(ue.data)) == mddObj)
{
prepareToDie();
this->Close(TRUE);
return 1;
}
}
if ((ue.type == usr_db_opened) || (ue.type == usr_db_closed))
{
newDBState((ue.type == usr_db_opened));
return 1;
}
if (ue.type == usr_close_viewers)
{
Close(TRUE);
return 1;
}
return 0;
}
// Virtual function, overload by derived classes if you need to.
void rviewDisplay::prepareToDie(void)
{
}
// Virtual function, overload by derived classes
int rviewDisplay::newProjection(void)
{
return 0;
}
int rviewDisplay::fileMenuInitHook(wxMenu *menu)
{
return 0;
}
int rviewDisplay::viewMenuInitHook(wxMenu *menu)
{
return 0;
}
int rviewDisplay::menuBarInitHook(void)
{
return 0;
}
// Support function for advanceProjection
const char *rviewDisplay::skipIndexMapping(const char *s)
{
const char *b, *d;
b = s+1;
while ((*b == ' ') || (*b == '\t')) b++;
d = b;
while ((*b >= '0') && (*b <= '9')) b++;
if (b == d) return NULL;
while ((*b == ' ') || (*b == '\t')) b++;
if (*b != ']') return NULL;
return b+1;
}
/*
* Change the chosen fixed coordinate according to the advancement mode:
* relative: coord += direction
* absolute: coord = direction
* reset: if (direction <= 0) then to start else to end
*/
int rviewDisplay::advanceProjection(int direction, int advmode)
{
const char *b, *d;
int cordnt;
r_Range value;
char tailbuff[STRINGSIZE];
unsigned int freeDims=0;
const char **dimDescs;
const r_Minterval useIv = getVirtualDomain();
if ((dimDescs = new const char*[dimMDD]) == NULL)
return 0;
// Find free dimensions in projection string
strcpy(projString, project->GetValue());
b = projString; value = 0;
while (*b != '\0')
{
cordnt = 0; // indicates it's a number
while ((*b == ' ') || (*b == '\t')) b++;
if (*b == '\0') break;
if (value < dimMDD) dimDescs[value] = b;
if (*b == '*') // not a number
{
b++; cordnt=1;
}
else
{
if ((*b == '-') || (*b == '+')) b++;
d = b;
while ((*b >= '0') && (*b <= '9')) b++;
if (b == d)
{
delete [] dimDescs; return 0;
}
}
while (*b == ' ') b++;
if (*b == '[')
{
if ((b = skipIndexMapping(b)) == NULL)
{
delete [] dimDescs; return 0;
}
}
else if (*b == ':')
{
b++;
while ((*b == ' ') || (*b == '\t')) b++;
if (*b == '*') b++;
else
{
if ((*b == '-') || (*b == '+')) b++;
d = b;
while ((*b >= '0') && (*b <= '9')) b++;
if (b == d)
{
delete [] dimDescs; return 0;
}
}
while ((*b == ' ') || (*b == '\t')) b++;
if (*b == '[')
{
if ((b = skipIndexMapping(b)) == NULL)
{
delete [] dimDescs; return 0;
}
}
}
else if (cordnt == 0)
{
freeDims |= (1<GetValue());
// Is the specified coordinate a free one?
if ((cordnt < 0) || (cordnt >= dimMDD) || ((freeDims & (1<SetValue(tailbuff);
}
b = dimDescs[cordnt];
value = atoi(b);
// Save tail
if (cordnt < dimMDD-1)
sprintf(tailbuff, ", %s", dimDescs[cordnt+1]);
else
tailbuff[0] = '\0';
// update the coordinate according to the advancement mode
if (advmode == display_advmode_relative)
value += direction;
else if (advmode == display_advmode_absolute)
value = direction;
else if (advmode == display_advmode_reset)
{
if (direction <= 0)
value = useIv[cordnt].low();
else
value = useIv[cordnt].high();
}
if ((value >= useIv[cordnt].low()) && (value <= useIv[cordnt].high()))
{
// this cast here is OK, doesn't compromise the function interface.
sprintf((char*)b, "%ld%s", value, tailbuff);
project->SetValue(projString);
delete [] dimDescs;
return 1;
}
delete [] dimDescs;
return 0;
}
void rviewDisplay::setDisplayTitle(const char *title)
{
char titleString[STRINGSIZE];
char *b;
if (title != NULL)
{
strcpy(rootTitle, title);
}
// Create the title postfix string
strcpy(titleString, rootTitle);
b = titleString + strlen(titleString);
if ((displayFlags & (display_flag_standalone | display_flag_update)) != 0)
{
*b++ = ' '; *b++ = '[';
if ((displayFlags & display_flag_standalone) != 0)
b += sprintf(b, "StAln");
if ((displayFlags & display_flag_update) != 0)
{
b += sprintf(b, "U");
if (qwindowID != -1)
b += sprintf(b, "d%dq%d", displayID, qwindowID);
*b++ = ' ';
}
*b++ = ']';
}
*b++ = '\0';
SetTitle(titleString);
}
void rviewDisplay::noLongerUpdate(void)
{
displayFlags &= ~display_flag_update;
setDisplayTitle();
}
int rviewDisplay::getIdentifier(void) const
{
return displayID;
}
int rviewDisplay::getDisplayCounter(void) const
{
return displayCounter;
}
void rviewDisplay::setQueryWindow(int qwid)
{
qwindowID = qwid;
setDisplayTitle();
}
void rviewDisplay::setMinimumViewerSize(int w, int h)
{
minViewX = w; minViewY = h;
}
int rviewDisplay::doSaveView(void)
{
char *name = ::wxFileSelector(lman->lookup("saveView"), (char*)(::wxDirExists(prefs->filePath.ptr()) ? prefs->filePath.ptr() : NULL), NULL, NULL, (char*)viewFileExtension);
if (name != NULL)
{
FILE *fp = fopen(name, "w");
if (fp != NULL)
{
fprintf(fp, "%s\n\n", view_HeaderLine);
int status = saveView(fp);
fclose(fp);
return status;
}
return -1;
}
return 0;
}
int rviewDisplay::doLoadView(void)
{
char *name = ::wxFileSelector(lman->lookup("loadView"), (char*)(::wxDirExists(prefs->filePath.ptr()) ? prefs->filePath.ptr() : NULL), NULL, NULL, (char*)viewFileExtension);
if (name != NULL)
{
FILE *fp = fopen(name, "r");
if (fp != NULL)
{
int status = parseViewFile(fp);
fclose(fp);
loadViewFinished();
newProjection();
return status;
}
return -1;
}
return 0;
}
int rviewDisplay::parseViewFile(FILE *fp)
{
char *buffer = new char[viewBuffSize];
unsigned int line = 0;
int status = -1;
if (fgets(buffer, viewBuffSize, fp) != NULL)
{
int len = strlen(buffer);
line++;
if (strncmp(view_HeaderLine, buffer, len-1) == 0)
{
while (!feof(fp))
{
if (fgets(buffer, viewBuffSize, fp) == NULL)
break;
line++;
char *b = buffer;
while (isspace((unsigned int)(*b))) b++;
if (*b != '\0')
{
char *key = b;
while (isalnum((unsigned int)(*b))) b++;
char *kend = b;
while (isspace((unsigned int)(*b))) b++;
if (*b != '=')
{
cerr << "Missing '=' at line " << line << endl;
}
else
{
*kend = '\0'; b++;
while (isspace((unsigned int)(*b))) b++;
len = strlen(b);
while ((len > 0) && (isspace((unsigned int)(b[len-1])))) b[--len] = '\0';
//cout << "key " << key << ", value " << b << endl;
if (readView(key, b) < 0)
{
delete [] buffer;
return -1;
}
}
}
}
status = 0;
}
}
delete [] buffer;
return status;
}
void rviewDisplay::loadViewFinished(void)
{
project->SetValue(projString);
}
void rviewDisplay::writeViewKey(FILE *fp, const char *key)
{
fprintf(fp, "%s\t=\t", key);
}
void rviewDisplay::writeViewParam(FILE *fp, const char *key, const char *value)
{
fprintf(fp, "%s\t=\t%s\n", key, value);
}
void rviewDisplay::writeViewParam(FILE *fp, const char *key, long value)
{
fprintf(fp, "%s\t=\t%ld\n", key, value);
}
void rviewDisplay::writeViewParam(FILE *fp, const char *key, double value)
{
fprintf(fp, "%s\t=\t%.15f\n", key, value);
}
void rviewDisplay::writeViewParam(FILE *fp, const char *key, unsigned int num, const long *values)
{
fprintf(fp, "%s\t=\t%ld", key, values[0]);
for (unsigned int i=1; ilookup("errorViewType"), value);
rviewErrorbox::reportError(buffer, getFrameName(), "readView");
return -1;
}
return 1;
}
else if (strcmp(key, view_ProjString) == 0)
{
strcpy(projString, value);
return 1;
}
else if (strcmp(key, view_WindowSize) == 0)
{
long wsize[2];
if (readVector(value, 2, wsize) == 0)
{
SetSize(wsize[0], wsize[1]);
return 1;
}
}
return 0;
}