/*************************************************************************** propedit.cc - object properties editor --------------------------------------------------------------------- May, 2000 Copyright (C) 2000 by Warlei Alves walves@usa.net Heavily modified by Salvador E. Tropea to compile without warnings. Some warnings were in fact bugs. For gcc 2.95.x and then 3.0.1. ***************************************************************************/ /*************************************************************************** * * * This program 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #define Uses_TEvent #define Uses_TProgram #define Uses_TDeskTop #define Uses_TView #define Uses_TScrollBar #define Uses_TKeys #define Uses_TDrawBuffer #define Uses_TDialog #define Uses_TEventQueue #define Uses_MsgBox #define Uses_TListBox #define Uses_TStringCollection #define Uses_TCollection #define Uses_TInputLine #define Uses_TPalette #define Uses_TValidator #include #include "dsgdata.h" #include "propedit.h" #include "dsgobjs.h" #include "propdlgs.h" #include "consted.h" #include "fdconsts.h" enum TDataEditorType { etNone, etStringEditor, // Short string value up to 60 bytes etIntegerEditor, // Integer value etOptionsEditor, // View options value etEventMaskEditor, // View eventMask value etStateEditor, // View initial state value ( some of them ) etGrowModeEditor, // View growMode value etDragModeEditor, // View dragMode value etHelpCtxEditor, // hc## value etCommandEditor, // cm## value etButtonFlagEditor, // Button flag value etWindowFlagEditor, // Window flag value etValidatorEditor, // TValidator type value etCharPtrEditor, // Null terminated string value etValidatorDataEditor, // TValidator data value (Filter | range) etStrCollectionEditor, // Generic string lists etLinkEditor, // Links for TDLabel etScrollBarEditor, // ScrollBars }; // Objects that can be a link for a TDLabel static TStringCollection * LinkList = 0; // Available V and H scrollbars static TStringCollection * ScrollList = 0; // Global object manager list static TLinkList * ObjLink = 0; // Current object editor static TObjEdit * ObjEdit; // To resolve (sprintf "%s") when there is nothing to do static char * blank = ""; //extern int TabOrder; /* functions ==============================================================*/ // Standard execDialog without free the dialog int execDialog_NoFree(TDialog * dialog, void *data) { int rst; TView * d = TProgram::application->validView(dialog); if (d) { if (data) d->setData(data); rst = TProgram::deskTop->execView(d); if ((rst!=cmCancel) && (data)) d->getData(data); return rst; } else return cmCancel; } // Standard execDialog int execDialog(TDialog * dialog, void *data) { int rst; TView * d = TProgram::application->validView(dialog); if (d) { if (data) d->setData(data); rst = TProgram::deskTop->execView(d); if ((rst!=cmCancel) && (data)) d->getData(data); TObject::CLY_destroy( d ); return rst; } else return cmCancel; } /* TLinkList ============================================================*/ // Sorter func by tabulation order static int byTabOrder(const void * key1, const void * key2) { TDsgObj * d1 = (TDsgObj *)((TDsgLink *)key1)->d; TDsgObj * d2 = (TDsgObj *)((TDsgLink *)key2)->d; bool d1CanTab = d1->tabStop(); bool d2CanTab = d2->tabStop(); if (!d1CanTab && d2CanTab) return -1; if (!d1CanTab && !d2CanTab) return 0; if (d1CanTab && !d2CanTab) return 1; short t1 = ((TDsgObjData *)d1->attributes)->tabOrder; short t2 = ((TDsgObjData *)d2->attributes)->tabOrder; if (d1CanTab && d2CanTab) { if ((t1 > t2) - (t1 < t2) == 0) { if (d1 == ObjEdit->object) return 1; if (d2 == ObjEdit->object) return -1; } else return (t1 > t2) - (t1 < t2); } return 0; } /* static int byCreationOrder(void * key1, void * key2) { c1 = ((TDsgObj *)((TDataLink *&)*key1)->d)->creationOrder; c2 = ((TDsgObj *)((TDataLink *&)*key2)->d)->creationOrder; return (c1 > c2) - (c1 < c2); } */ // Test functions static Boolean matchView(void * link, void * view) { return (((TDsgLink *)link)->v == view); } static Boolean matchDsgObj(void * link, void * dsgObj) { return (((TDsgLink *)link)->d == dsgObj); } static Boolean matchScroll(void * link, void * aName) { TDsgObj * d = ((TDsgLink *)link)->d; return ( (d->viewType == vtVScroll || d->viewType == vtHScroll) && strcmp( ((TDsgObjData*)d->attributes)->thisName, (char *)aName ) == 0 ); } static Boolean matchLabel(void * link, void * aLink) { TDsgObj * d = ((TDsgLink *)link)->d; return ( d->viewType == vtLabel && strcmp( ((TDLabelData *)d->attributes)->link, (char *)aLink ) == 0 ); } // Find functions TDsgLink * TLinkList::viewFind(void * aView) // by View { return (TDsgLink *)firstThat(&matchView, aView); } TDsgLink * TLinkList::dsgObjFind(void * aDsgObj) // by DsgObj { return (TDsgLink *)firstThat(&matchDsgObj, aDsgObj); } TDsgLink * TLinkList::linkFind(char * aName) // Look for a label { return (TDsgLink *)firstThat(&matchLabel, aName); } TDsgLink * TLinkList::scrollFind(char * aScroll) // Look for a ScrollBar { return (TDsgLink *)firstThat(&matchScroll, aScroll); } // Remove the object from and notificates all others in the list void TLinkList::removeMe(TDsgObj * aDsgObj) { int index; void * link = firstThat(&matchDsgObj, aDsgObj); if (link) { TDsgObjData * data = (TDsgObjData *)aDsgObj->attributes; // atFree(indexOf(link)); this->free(link); switch(aDsgObj->viewType) { case vtVScroll...vtHScroll: if (ScrollList->search(&data->thisName, index)) { removeNotify(ScrollList, index); ScrollList->atRemove(index); } break; case vtStatic: break; case vtLabel: break; default: if (LinkList->search(&data->thisName, index)) { removeNotify(LinkList, index); LinkList->atRemove(index); } } } } // Inserts a pair of pointers from the (TView, TDsgObj) descendant to the list. // This is necessary because one TView descendant that also inherits the // TDsgObj code cannot be directly refered as a TDsgObj outside its context. void TLinkList::add(TView * aView, TDsgObj * aDsgObj) { if (!aView || !aDsgObj) return; if (viewFind(aView) != 0) return; TDsgLink * link = new TDsgLink; link->v = aView; link->d = aDsgObj; insert(link); TDsgObjData * data = (TDsgObjData *)aDsgObj->attributes; switch(aDsgObj->viewType) { case vtVScroll...vtHScroll: ScrollList->insert(&data->thisName); break; case vtStatic: break; case vtButton: break; case vtLabel: strcpy( ((TDLabelData *)aDsgObj->attributes)->link, blank ); break; case vtMemo: strcpy( ((TDMemoData *)aDsgObj->attributes)->hScroll, blank ); strcpy( ((TDMemoData *)aDsgObj->attributes)->vScroll, blank ); LinkList->insert(&data->thisName); break; case vtListBox: strcpy( ((TDListBoxData *)aDsgObj->attributes)->scrollBar, blank ); LinkList->insert(&data->thisName); break; default: LinkList->insert(&data->thisName); } } void TLinkList::freeItem(void * item) { delete (char *)item; } // To reorganize the views in a correct tabulation order void TLinkList::doReOrder() { short Tab = 0; int i; TDsgLink * dsg; TDsgObjData * dsgData; if (count == 0) return; sort(byTabOrder); for (i = 0; i < count; i++) { dsg = (TDsgLink *)at(i); dsgData = (TDsgObjData *)dsg->d->attributes; if (dsg->d->tabStop()) { dsgData->tabOrder = Tab; Tab++; } } for (i = count - 1; i > 0; i--) { dsg = (TDsgLink *)at(i); dsg->v->makeFirst(); } } // Sorting with qsort void TLinkList::sort(ccSortFunc Compare) { qsort(items, count, sizeof(void *), Compare); } // Try to reorganize the objects in an ideal creation order void TLinkList::sortForBuild() { #if 0 #define _item_move_(a) do { remove(tmp); atInsert(a, tmp); i++; } while(0) int i = 0; char * s1, * s2; TViewData * attr = 0; if (count <= 1) return; doReOrder(); void * tmp; do { attr = (TViewData *)((TDsgLink *)items[i])->d->attributes; if (tmp = linkFind(attr->thisName)) _item_move_( ((i + 1) < count) ? i + 1 : i ); i++; } while (i < count); i = 0; do { s1 = blank; s2 = blank; attr = (TViewData *)((TDsgLink *)items[i])->d->attributes; if ((((TDsgLink *)items[i])->d)->viewType == vtListBox) s1 = ((TDListBoxData *)attr)->scrollBar; else if ((((TDsgLink *)items[i])->d)->viewType == vtMemo) { s1 = ((TDMemoData *)attr)->vScroll; s2 = ((TDMemoData *)attr)->hScroll; } if (tmp = scrollFind(s2)) { _item_move_( ((i - 1) >= 0) ? i - 1: 0 ); if (s1 != blank) i--; } if (tmp = scrollFind(s1)) { _item_move_( ((i - 1) >= 0) ? i - 1: 0 ); } i++; } while (i < count); #undef _item_move_ #endif } // Called by removeMe to notify dependencies void TLinkList::removeNotify(TCollection * aCollection, int Index) { int i; TDsgObj * d; for (i = 0; i < count; i++) { d = (TDsgObj *)((TDsgLink *)at(i))->d; if (aCollection == LinkList && d->viewType == vtLabel) { if ( strcmp( ((TDLabelData *)d->attributes)->link, (char *)aCollection->at(Index) ) == 0 ) strcpy ( ((TDLabelData *)d->attributes)->link, blank ); } else if (aCollection == ScrollList && d->viewType == vtListBox) { if ( strcmp( ((TDListBoxData *)d->attributes)->scrollBar, (char *)aCollection->at(Index) ) == 0 ) strcpy ( ((TDListBoxData *)d->attributes)->scrollBar, blank ); } else if (aCollection == ScrollList && d->viewType == vtMemo) { if ( strcmp( ((TDMemoData *)d->attributes)->hScroll, (char *)aCollection->at(Index) ) == 0 ) strcpy ( ((TDMemoData *)d->attributes)->hScroll, blank ); if ( strcmp( ((TDMemoData *)d->attributes)->hScroll, (char *)aCollection->at(Index) ) == 0 ) strcpy ( ((TDMemoData *)d->attributes)->vScroll, blank ); } } } // Called when an object has its "name" changed in the editor void TLinkList::linkChangedName(char * oldName, char * newName) { int i; pack(); for (i = 0; i < count; i++) { TDsgLink * d = (TDsgLink *)items[i]; TDsgObj * obj = d->d; if (obj->viewType == vtListBox) { if (strcmp( (char *)((TDListBoxData *)obj->attributes)->scrollBar, oldName ) == 0) strcpy( (char *)((TDListBoxData *)obj->attributes)->scrollBar, newName); } else if (obj->viewType == vtMemo) { if (strcmp( (char *)((TDMemoData *)obj->attributes)->hScroll, oldName ) == 0) strcpy( (char *)((TDMemoData *)obj->attributes)->hScroll, newName); if (strcmp( (char *)((TDMemoData *)obj->attributes)->vScroll, oldName ) == 0) strcpy( (char *)((TDMemoData *)obj->attributes)->vScroll, newName); } else if (obj->viewType == vtLabel) { if (strcmp( (char *)((TDLabelData *)obj->attributes)->link, oldName ) == 0) strcpy( (char *)((TDLabelData *)obj->attributes)->link, newName); } } } /* ObjectLinker -----------------------------------------------------------*/ TLinkList * ObjectLinker() { return ObjLink; } /* TInplaceEdit ===========================================================*/ // A quick editor for int values and short string values // Nor Nor Sel Arrows #define cpInplaceEdit "\x06\x06\x07\x05" TInPlaceEdit::TInPlaceEdit(const TRect& bounds, ushort aMaxLen, TValidator * aValidator): TInputLine(bounds, aMaxLen) { SetValidator(aValidator); } void TInPlaceEdit::handleEvent(TEvent& event) { if (event.what == evKeyDown) { switch(event.keyDown.keyCode) { case kbEnter: endState = cmOK; clearEvent(event); break; case kbEsc: endState = cmCancel; clearEvent(event); break; case '-': if ((validator) && curPos != 0) clearEvent(event); } } if ((event.what == evMouseDown) && (!containsMouse(event)) ) endState = cmCancel; TInputLine::handleEvent(event); } TPalette& TInPlaceEdit::getPalette() const { static TPalette palette( cpInplaceEdit, sizeof(cpInplaceEdit) - 1 ); return palette; } ushort TInPlaceEdit::execute() { TEvent e; endState = 0; do { getEvent(e); handleEvent(e); } while (endState == 0); return endState; } /* Inplace editors --------------------------------------------------------*/ bool IntegerEditor(int& value, TPoint place, TGroup * host) { bool rst = false; char strval[20]; TRect r(place.x, place.y, place.x + (host->size.x - place.x - 1), place.y + 1); sprintf(strval, "%i", value); TFilterValidator * val = new TFilterValidator("-0123456789"); TInPlaceEdit * editor = new TInPlaceEdit(r, 6, val); editor->setData(&strval); rst = ( host->execView(editor) == cmOK ); if (rst) { editor->getData(&strval); value = atoi(strval); } TObject::CLY_destroy( editor ); return rst; } bool StringEditor(char * string, TPoint place, TGroup * host, ushort aMaxLen) { bool rst = false; TRect r(place.x, place.y, place.x + (host->size.x - place.x - 1), place.y + 1); TInPlaceEdit * editor = new TInPlaceEdit(r, aMaxLen, 0); editor->setData(string); rst = ( host->execView(editor) == cmOK ); if (rst) editor->getData(string); TObject::CLY_destroy( editor ); return rst; } /* TStructMap =============================================================*/ // Configurable data mapper used to edit values in the TDsgObj::attributes // field class TStructMap { public: TStructMap(const char * Label, // int OffSet, int DataSize, TDataEditorType aEditorType, bool ReadOnly = false, TStructMap *Next = 0); ~TStructMap(); TStructMap * prev; TStructMap * next; int index; int offset; int dataSize; int editorType; char * label; bool readOnly; }; TStructMap::TStructMap(const char * Label, int DataSize, TDataEditorType aEditorType, bool ReadOnly , TStructMap *Next ) { label = newStr(Label); offset = 0; dataSize = DataSize; editorType = aEditorType; index = 0; readOnly = ReadOnly; prev = NULL; next = Next; if (next != 0) { next->prev = this; next->offset = offset + dataSize; next->index = index + 1; } } TStructMap::~TStructMap() { delete[] label; if (next) delete(next); } TStructMap& operator + ( TStructMap& map1, TStructMap& map2 ) { TStructMap *map = &map1; while (map->next) map = map->next; map->next = &map2; map2.offset = map->offset + map->dataSize; map2.prev = map; if (map2.dataSize > 0) { while ((map->dataSize == 0) && (map->prev)) map = map->prev; map2.index = map->index + 1; } return map2; } /* Data mappers -----------------------------------------------------------*/ // Commom TView data map initialization code fragment #define _separator_(a) *new TStructMap(a, 0, etNone, true, 0) #define _viewmap_() \ _separator_("TView data")+ \ *new TStructMap("Left", sizeof(int), etIntegerEditor)+\ *new TStructMap("Top", sizeof(int), etIntegerEditor)+\ *new TStructMap("Width", sizeof(int), etIntegerEditor)+\ *new TStructMap("Height", sizeof(int), etIntegerEditor)+\ *new TStructMap("ClassName", MAX_LABEL_LENGTH, etStringEditor, true)+\ *new TStructMap("Name", MAX_LABEL_LENGTH, etStringEditor)+\ *new TStructMap("Options", sizeof(ushort), etOptionsEditor)+\ *new TStructMap("EventMask", sizeof(ushort), etEventMaskEditor)+\ *new TStructMap("State", sizeof(ushort), etStateEditor)+\ *new TStructMap("GrowMode", sizeof(ushort), etGrowModeEditor)+\ *new TStructMap("DragMode", sizeof(ushort), etDragModeEditor)+\ *new TStructMap("HelpContext", sizeof(ushort), etHelpCtxEditor) /* TPoint origin;\ TPoint size;\ TNameStr className;\ TNameStr thisName;\ ushort options;\ ushort eventMask;\ ushort state;\ ushort growMode;\ ushort dragMode;\ ushort helpCtx\ */ static const TStructMap * TViewMap = &(_viewmap_()); static const TStructMap * TDialogMap = &( _viewmap_()+ _separator_("TDialog data") + *new TStructMap("Title", MAX_TITLE_LENGTH, etStringEditor) + *new TStructMap("Flags", sizeof(ushort), etWindowFlagEditor, 0) ); static const TStructMap * TLabelMap = &( _viewmap_()+ _separator_("TLabel data")+ *new TStructMap("Text", MAX_LABEL_LENGTH, etStringEditor)+ *new TStructMap("Link", MAX_LABEL_LENGTH, etLinkEditor, 0) ); static const TStructMap * TInputMap = &( _viewmap_()+ _separator_("TInputLine data") + *new TStructMap("TabOrder", sizeof(int), etIntegerEditor) + *new TStructMap("MaxLen", sizeof(int), etIntegerEditor) + *new TStructMap("Validator", sizeof(ushort), etValidatorEditor) + *new TStructMap("ValidatorData", MAX_LABEL_LENGTH, etValidatorDataEditor, 0) ); static const TStructMap * TMemoMap = &( _viewmap_()+ _separator_("TMemo data") + *new TStructMap("TabOrder", sizeof(int), etIntegerEditor) + *new TStructMap("HScroll", MAX_LABEL_LENGTH, etScrollBarEditor, 0) + *new TStructMap("VScroll", MAX_LABEL_LENGTH, etScrollBarEditor, 0) + *new TStructMap("BufSize", sizeof(uint32), etIntegerEditor) ); // *new TStructMap("Text", sizeof(char *), etCharPtrEditor, 0) ); static const TStructMap * TStaticMap = &( _viewmap_()+ _separator_("TStaticText data") + *new TStructMap("Text", sizeof(char *), etCharPtrEditor, 0) ); static const TStructMap * TButtonMap = &( _viewmap_()+ _separator_("TButton data") + *new TStructMap("TabOrder", sizeof(int), etIntegerEditor) + *new TStructMap("Title", MAX_LABEL_LENGTH, etStringEditor) + *new TStructMap("Command", sizeof(ushort), etCommandEditor) + *new TStructMap("Flags", sizeof(ushort), etButtonFlagEditor) ); static const TStructMap * TListBoxMap = &( _viewmap_()+ _separator_("TListBox Data") + *new TStructMap("TabOrder", sizeof(int), etIntegerEditor) + *new TStructMap("Columns", sizeof(short), etIntegerEditor) + *new TStructMap("ScrollBar", MAX_LABEL_LENGTH, etScrollBarEditor) ); static const TStructMap * TClusterMap = &( _viewmap_()+ _separator_("TCluster Data") + *new TStructMap("TabOrder", sizeof(int), etIntegerEditor) + *new TStructMap("Items", sizeof(void *), etStrCollectionEditor) ); #undef _viewmap_ /* TObjEditView ===========================================================*/ TObjEditView::TObjEditView(const TRect& bounds, TScrollBar * v): TView(bounds) { sb = v; separator = size.x / 2; eventMask = evMouse | evKeyboard | evCommand | evBroadcast; currentMap=0; } void TObjEditView::setMap(const TStructMap * aMap, void * Data) { data = Data; if (!data) { dataMap = 0; currentMap = 0; drawView(); return; } while (aMap->next) aMap = aMap->next; sb->setRange(1, aMap->index); while (aMap->prev) aMap = aMap->prev; dataMap = aMap; if (aMap->dataSize == 0) while ((aMap->next) && (aMap->dataSize == 0)) aMap = aMap->next; currentMap = aMap; drawView(); } void calcPlace(TPoint& p, short column, short line, const TStructMap * map) { p.x = column + 1; p.y = line; while (map->next) { if (map->dataSize == 0) p.y++; map = map->next; if (map->index >= line) break; } } int findStr(TCollection * col, const char * cmp) { int i, c = col->getCount(); if (c == 0) return -1; for (i = 0; i < c; i++) if (strcmp(cmp, (char *)col->at(i)) == 0) return i; return 0; } void TObjEditView::editItem(const TStructMap * map) { ushort Val; TListBoxRec rec; void * v; TMemoData m; char * c; int i; TPoint place; char oldName[30]; #define _editlink_(list, editor) \ if (list->getCount() == 0) break; \ rec.items = list; \ rec.selection = findStr(list, (char*)ldata); \ if (rec.selection < 0) break; \ chg = (execDialog(editor(), &rec) == cmOK); \ if (chg) strcpy((char *)ldata, (char *)list->at(rec.selection)); \ break; #define _do_(editor) chg = (execDialog(editor(), ldata) == cmOK); break; #define _constsel_(list, editor) \ rec.items = list(); \ rec.selection = list()->getIndex((ushort)(int)ldata); \ chg = (execDialog(editor(), &rec) == cmOK); \ if (chg) memcpy(ldata, &rec.selection, sizeof(ushort)); break; if (map->readOnly) { messageBox("Ops! Read only value.", mfOKButton); return; } void * ldata = (void *)((char *)data + map->offset); bool chg = false; switch(map->editorType) { case etStringEditor: calcPlace(place, separator, map->index, dataMap); if (map->index == 6) strcpy(oldName, (char *)ldata); chg = StringEditor((char *)ldata, place, owner, map->dataSize); if ( (chg) && (map->index == 6 || vtCurrent == vtVScroll || vtCurrent == vtHScroll ) ) { if (strlen((char *)ldata) == 0) { strcpy((char *)ldata, oldName); chg = false; break; } else if (strcmp((char *)ldata, oldName) != 0) ObjLink->linkChangedName(oldName, (char *)ldata); } if (chg) message(owner, evMessage, cmValueChanged, 0); break; case etIntegerEditor: calcPlace(place, separator, map->index, dataMap); if (vtCurrent == vtListBox && map->index == 14) i = (short)(int)ldata; else i = (int)ldata; chg = IntegerEditor(i, place, owner); if (vtCurrent == vtListBox && map->index == 14) ldata = (void *)i; else ldata = (void *)i; if (chg) message(owner, evMessage, cmValueChanged, 0); break; case etOptionsEditor: _do_(OptionsEditor); case etEventMaskEditor: memcpy(&Val, ldata, sizeof(ushort)); if (Val & evCommand) { Val &= ~evCommand; Val |= 0x20; } if (Val & evBroadcast) { Val &= ~evBroadcast; Val |= 0x40; } chg = (execDialog(EventMaskEditor(), ldata) == cmOK); if (chg) { if (Val & 0x20) { Val &= ~0x20; Val |= evCommand; } if (Val & 0x40) { Val &= ~0x40; Val |= evBroadcast; } memcpy(ldata, &Val, sizeof(ushort)); } break; case etStateEditor: _do_(StateEditor); case etGrowModeEditor: _do_(GrowModeEditor); case etDragModeEditor: _do_(DragModeEditor); case etHelpCtxEditor: _constsel_(HelpCtxsList, HelpCtxEditor); case etCommandEditor: _constsel_(CommandsList, CommandEditor); case etButtonFlagEditor: _do_(ButtonFlagEditor); case etWindowFlagEditor: _do_(WindowFlagEditor); case etValidatorEditor: _do_(ValidatorEditor); case etValidatorDataEditor: break; case etStrCollectionEditor: chg = (execDialog(ItemsEditor(), ldata) == cmOK); if (chg) message(owner, evMessage, cmValueChanged, 0); break; case etCharPtrEditor: c = (char *)ldata; strcpy(m.buffer, c); c = (char *)m.buffer; v = c; while (c[0]) // Turning '\x3' to "\x3" { if (c[0] == 3/*&& (c + 3 - v) < 1024*/) { memmove(c + 3, c + 1, strlen(c) + 1); memcpy(c, "\\x3", 3); } c++; } c = (char *)v; m.length = strlen(c); chg = (execDialog(CharPtrEditor(), &m) == cmOK); if (chg) { if (m.length == 0) strcpy(c, ""); else // Turning simbolic chars to raw { delete[] c; c = (char *)m.buffer; while (c[0]) // eating CR chars { if (c[0] == '\x0d') memmove(c, c + 1, strlen(c - 1)); c++; } c = (char *)m.buffer; while (c[0]) // Turning "\x3" to '\x3' { i = 0; if (c[0]==92) { while (c[i] != '3') { if (c[i] == 0) break; i++; } if (i <= 4) { c[0] = 3; memmove(&c[1], &c[i+1], strlen(c) - i); } } c++; } ldata=(void *)newStr(m.buffer); } message(owner, evMessage, cmValueChanged, 0); } break; case etLinkEditor: _editlink_(LinkList, LinkEditor); case etScrollBarEditor: _editlink_(ScrollList, ScrollEditor); } if (chg) drawView(); #undef _editlink_ #undef _do_ } const char * TObjEditView::getValueFor(const TStructMap * map) { static char buf[60]; static ushort ushrtval; static int intval; static void * ptrval; static void * ldata; ldata = data; ldata = (void *)((char *)ldata + map->offset); strcpy(buf, ""); if (map->editorType == etIntegerEditor) { memcpy(&intval, ldata, map->dataSize); sprintf(buf, "%i", intval); } else if ((map->editorType >= etOptionsEditor) && (map->editorType <= etValidatorEditor)) { memcpy(&ushrtval, ldata, map->dataSize); switch(map->editorType) { case etOptionsEditor: return OptionsStr(ushrtval); case etEventMaskEditor: return EventMaskStr(ushrtval); case etStateEditor: return StateStr(ushrtval); case etGrowModeEditor: return GrowModeStr(ushrtval); case etDragModeEditor: return DragModeStr(ushrtval); case etHelpCtxEditor: return HelpCtxStr(ushrtval); case etCommandEditor: return CommandStr(ushrtval); case etButtonFlagEditor: return ButtonFlagStr(ushrtval); case etWindowFlagEditor: return WindowFlagStr(ushrtval); case etValidatorEditor: return ValidatorStr(ushrtval); } } else if (map->editorType == etStrCollectionEditor || map->editorType == etCharPtrEditor) { memcpy(&ptrval, ldata, map->dataSize); if (map->editorType == etCharPtrEditor) return CharPtrStr(ptrval); else return ItemsStr(ptrval); } else if ( map->editorType == etStringEditor || map->editorType == etValidatorDataEditor ) { memset(&buf, 0, 60); memcpy(&buf, ldata, map->dataSize); return buf; } else if ( map->editorType == etScrollBarEditor || map->editorType == etLinkEditor ) { if (strlen((char *)ldata) > 0) return strcpy(buf, (char *)ldata); } return buf; } class TLDrawBuffer: public TDrawBuffer { public: ushort getData(ushort i) { return data[i]; } }; #define _lo_(a) ((uchar *)&a)[0] void TObjEditView::draw() { TLDrawBuffer b; const TStructMap * curMap; const TStructMap * cur; int r, l, tmp, line = 0; char lstr[100], rstr[100]; char lfmt[10], rfmt[10]; ushort attr; if (separator > size.x) separator = size.x / 2; r = (size.x - separator) + separator; l = separator; curMap = currentMap; if ((curMap) && size.y > 0) { cur = curMap; while (cur->prev) cur = cur->prev; do { if (cur->dataSize == 0) { tmp = (size.x - strlen(cur->label)) / 2; b.moveChar(0, 0x20, 0x3e, tmp); b.moveBuf(tmp, cur->label, 0x3e, strlen(cur->label)); b.moveChar(tmp + strlen(cur->label), 0x20, 0x3e, tmp + 1); attr = b.getData(l); if (_lo_(attr) == 0x20) b.moveChar(l, 0xb3, 0x31, 1); writeLine(0, line, size.x, 1, b); line++; } else { sprintf(lfmt, "%%-%is", l - 1); sprintf(lstr, lfmt, cur->label); sprintf(rfmt, "%%-%is", r); char *tmp=newStr(getValueFor(cur)); if (tmp && strlen(tmp)>=(size_t)r) tmp[r-1]=0; sprintf(rstr, rfmt, tmp ? tmp : "ERROR"); DeleteArray(tmp); if (cur == curMap) attr = 0x71; else attr = 0x1f; b.moveBuf(0, lstr, attr, l); if (cur == curMap) attr = 0x71; else attr = 0x13; b.moveChar(l, 0xb3, attr, 1); if (cur == curMap) attr = 0x71; else attr = 0x1e; b.moveBuf(l + 1, rstr, attr, r); writeLine(0, line, size.x, 1, b); line++; } if (line > size.y - 1) break; cur = cur->next; } while (cur); b.moveChar(0, 0x20, 0x1f, size.x); b.moveChar(l, 0xb3, 0x13, 1); writeLine(0, line, size.x, size.y - line, b); } else TView::draw(); } #undef _lo_ const TStructMap * itemForLine(int line, const TStructMap * Map) { ushort i = 1; if (line == 0 || Map == 0) return 0; while (Map->next) { Map = Map->next; if (i++ == line) break; } if (Map->dataSize != 0) return Map; else return 0; } #define _endcase_(a) if (currentMap->dataSize == 0) \ while ((currentMap->a) && (currentMap->dataSize == 0))\ currentMap = currentMap->a; sb->setValue(currentMap->index); \ drawView(); clearEvent(event) void TObjEditView::handleEvent(TEvent& event) { const TStructMap * t; ushort i; TView::handleEvent(event); if (!currentMap) return; TPoint Locate; if (event.what == evBroadcast && event.message.command == cmScrollBarChanged && event.message.infoPtr == sb) { i = sb->value; t = dataMap; while ((t->index != i) && (t->next)) t = t->next; if ((t->index == i) && (t != currentMap)) { currentMap = t; drawView(); } } else if (event.what == evMouseDown) { Locate = makeLocal(event.mouse.where); if (Locate.x == separator) { do { Locate = makeLocal(event.mouse.where); if ((Locate.x >= 1) && (Locate.x <= (size.x - 2))) { separator = Locate.x; drawView(); } } while ( mouseEvent( event, evMouseMove ) ); } else { t = itemForLine(Locate.y, dataMap); if ((t) && t != currentMap) { sb->setValue(t->index); currentMap = t; drawView(); } else if ((t == currentMap) && (event.mouse.doubleClick) && (event.mouse.buttons == mbLeftButton)) editItem(currentMap); } } else if (event.what == evKeyboard) { switch(event.keyDown.keyCode) { case kbUp: if (currentMap->prev) { currentMap = currentMap->prev; if (currentMap->dataSize == 0) if (currentMap->prev) currentMap = currentMap->prev; _endcase_(next); } break; case kbDown: if (currentMap->next) { currentMap = currentMap->next; _endcase_(next); } break; case kbPgUp: while (currentMap->prev) currentMap = currentMap->prev; _endcase_(next); break; case kbPgDn: while (currentMap->next) currentMap = currentMap->next; _endcase_(prev); break; case kbEnter: clearEvent(event); if (currentMap->dataSize > 0) editItem(currentMap); break; case kbDel: if (currentMap->editorType == etScrollBarEditor || currentMap->editorType == etLinkEditor) strcpy((char *)data + currentMap->offset, blank); drawView(); clearEvent(event); break; } } } #undef _endcase_ /* TObjedit ===============================================================*/ TObjEdit::TObjEdit(TDsgObj * Obj): TWindowInit(&TObjEdit::initFrame), TWindow( TRect(55, 0, 80, 23), _("Object editor"), 0 ) { flags &= ~wfClose; flags |= wfGrow; if (!LinkList) LinkList = new TStringCollection(0, 1); else LinkList->removeAll(); if (!ScrollList) ScrollList = new TStringCollection(0, 1); else ScrollList->removeAll(); LinkList->duplicates = False; ScrollList->duplicates = False; if (!ObjLink) ObjLink = new TLinkList(); else ObjLink->removeAll(); TScrollBar * sb = new TScrollBar( TRect(24, 1, 25, 19) ); insert(sb); sb->growMode |= gfGrowHiY; TRect r = getExtent(); r.grow(-1, -1); r.b.y -= 3; dataView = new TObjEditView( r, sb ); dataView->growMode |= (gfGrowHiY | gfGrowHiX); dataView->options |= ofPreProcess | ofPostProcess | ofFramed; ObjEdit = this; insert(dataView); setObjData(Obj); } void TObjEdit::handleEvent(TEvent& event) { TWindow::handleEvent(event); if (object == 0) return; if (event.what == evMessage && event.message.command == cmValueChanged) { object->dsgUpdate(); clearEvent(event); } } void TObjEdit::setObjData(TDsgObj * Obj) { const TStructMap * Map = 0; if ((!Obj) || object == Obj) return; dataView->setMap(0, 0); object = Obj; switch (Obj->viewType) { case vtLabel: Map = TLabelMap; break; case vtInput: Map = TInputMap; break; case vtMemo: Map = TMemoMap; break; case vtStatic: Map = TStaticMap; break; case vtButton: Map = TButtonMap; break; case vtListBox: Map = TListBoxMap; break; case vtRadioButton: Map = TClusterMap; break; case vtCheckBox: Map = TClusterMap; break; case vtDialog: Map = TDialogMap; break; default: Map = TViewMap; } if (!Map) { messageBox("Sem mapa!", mfOKButton); dataView->setMap(0, 0); return; } #if 0 int i = 0; TStructMap * m = Map; char c[100]; m = Map; while (m->prev) m = m->prev; while (m) { i += m->dataSize; m = m->next; }; if (i != Obj->getAttrSize()) { sprintf(c, "diferenca mapa: %i registro: %i", i, Obj->getAttrSize()); messageBox(c, mfOKButton); } #endif dataView->vtCurrent = Obj->viewType; dataView->setMap(Map, Obj->attributes); }