/* * FieldView.cpp * * Copyright (C) 1999 Stephen F. White * * 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. * * This program 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 this program (see the file "COPYING" for details); if * not, write to the Free Software Foundation, Inc., 675 Mass Ave, * Cambridge, MA 02139, USA. */ #include "stdafx.h" #include "FieldView.h" #include "swt.h" #include "resource.h" #include "FieldViewItem.h" #include "Node.h" #include "Proto.h" #include "Field.h" #include "FieldValue.h" #include "FieldCommand.h" #include "MFieldCommand.h" #include "Path.h" #include "Scene.h" #include "SFNode.h" #define CB_WIDTH 9 #define CB_HEIGHT 9 #define CB_SPACING 3 #define CB_ARRAY_INSERT (CB_WIDTH + CB_SPACING * 3) static void headerCallback(void *data, int pos, int width) { ((FieldView *) data)->OnHeaderChange(pos, width); } static void textCommandCallback(void *data, int command) { if (command) { ((FieldView *) data)->StopEditing(); } else { ((FieldView *) data)->AbortEditing(); } } static void textFocusCallback(void *data, int value) { if (!value) ((FieldView *) data)->StopEditing(); } static void expose(void *data, int x, int y, int width, int height) { ((FieldView *) data)->OnDraw(x, y, width, height); } static void keyCB(void *data, int key, int value, int x, int y, int modifiers) { if (key == SW_MOUSE1) { if (value) { ((SceneView *) data)->OnLButtonDown(x, y, modifiers); } else { ((SceneView *) data)->OnLButtonUp(x, y, modifiers); } } else if (value) { ((SceneView *) data)->OnKeyDown(key, x, y, modifiers); } else { ((SceneView *) data)->OnKeyUp(key, x, y, modifiers); } } static void mouseCB(void *data, int x, int y, int modifiers) { ((SceneView *) data)->OnMouseMove(x, y, modifiers); } static void mouseEnterCB(void *data, int value) { if (value) { ((SceneView *) data)->OnMouseEnter(); } else { ((SceneView *) data)->OnMouseLeave(); } } FieldView::FieldView(Scene *scene, SWND parent) : SceneView(scene, parent) { int width, height; int fg, bg; swGetSize(parent, &width, &height); _scroller = swCreateScrolledWindow(0, 0, width, height, parent); _window = swCreateCanvas("", 0, 0, width, height, _scroller); swScrolledWindowSetChild(_scroller, _window); swSetExposeCallback(_window, expose); swSetKeyCallback(_window, keyCB); swSetMouseCallback(_window, mouseCB); swSetEnterCallback(_window, mouseEnterCB); swSetClientData(_window, this); _state = NORMAL; _trackPoint.x = _trackPoint.y = 0; _trackValue = NULL; _selectedField = -1; _selectedNode = NULL; _selectedItem = -1; _pageHeight = 0; _scrollY = 0; _scrollRatio = 1.0f; fg = swGetWindowColor(parent, SW_COLOR_WINDOW_FG); bg = swGetWindowColor(parent, SW_COLOR_WINDOW_BG); int mapFrom[2] = { 0x00ffffff, 0x00ff0000 }; int mapTo[2] = { fg, bg }; _halftoneBitmap = swLoadMappedBitmap(parent, IDB_HALFTONE, mapFrom, mapTo, 2); _itemHeight = swGetFontHeight(swGetDefaultFont()) + 2; _floatWidth = swGetFontHeight(swGetDefaultFont()) * 4; _height = _itemHeight; _header = NULL; // this is so we can handle OnSize() correctly _header = swCreateHeader(0, 0, width, _itemHeight, _window); swHeaderSetCallback(_header, headerCallback); swHeaderSetClientData(_header, this); int cx = MIN(width, 120); swHeaderInsertItem(_header, 0, "Field", cx); swHeaderInsertItem(_header, 1, "Value", width - cx); _width = 350; _uFont = swFindFont("Helvetica", SW_UNDERLINE, 10); _fieldViewActive=true; _cursorArrow = swLoadCursor(SW_CURSOR_ARROW); _cursorHMove = swLoadCursor(SW_CURSOR_DBL_ARROW_HORZ); _cursorIsArrow = true; } FieldView::~FieldView() { DeleteView(); DeleteFields(); swDestroyCursor(_cursorArrow); swDestroyCursor(_cursorHMove); // swDestroyWindow(_window); // _window = NULL; // swDestroyWindow(_scroller); // _scroller = NULL; // swDestroyWindow(_wnd); // _wnd = NULL; } void FieldView::DeleteFields() { for (int i = 0; i < _fields.size(); i++) { delete _fields[i]; } _fields.resize(0); } void FieldView::DeleteView() { _fieldViewActive=false; if (_halftoneBitmap!=NULL) { swDestroyBitmap(_halftoneBitmap); _halftoneBitmap=NULL; } if (_header!=NULL) { swHeaderSetCallback(_header,NULL); swDestroyHeader(_header); _header=NULL; } if (_uFont!=NULL) { swDeleteFont(_uFont); _uFont=NULL; } if (_window != NULL) swDeleteCallbacks(_window); if (_scroller != NULL) swDeleteCallbacks(_scroller); if (_wnd != NULL) swDeleteCallbacks(_wnd); swDestroyWindow(_window); _window = NULL; swDestroyWindow(_scroller); _scroller = NULL; } void FieldView::OnDraw(int x, int y, int width, int height) { int n = _items.size(); SDC dc = swCreateDC(_window); SDC bdc = swCreateBitmapDC(dc, x + width, y + height); if (bdc == NULL) { swDestroyDC(dc); return; } swSetFGColor(bdc, swGetWindowColor(_window, SW_COLOR_WINDOW_BG)); swFillRect(bdc, x, MAX(y, _itemHeight), width, height); for (int i = _scrollY; i < _scrollY + _items.size() + 1 && i < n; i++) { DrawItem(i, bdc); } swCopyRect(bdc, dc, x, y, x, y, width, height); swDestroyDC(bdc); swDestroyDC(dc); } void FieldView::OnUpdate(SceneView *sender, int type, Hint *hint) { const Path *sel = _scene->getSelection(); Node *node = sel ? sel->getNode() : NULL; int field = sel ? sel->getField() : -1; Rect rect; FieldUpdate *fieldUpdate; NodeUpdate *nodeUpdate; if (_state == EDITING) StopEditing(); switch (type) { case UPDATE_ALL: UpdateAll(); break; case UPDATE_SELECTION: if (_selectedNode != node || _selectedField != field) { _selectedNode = node; _selectedField = field; swSetScrollPosition(_scroller, 0, 0); UpdateAll(); } break; case UPDATE_FIELD: fieldUpdate = (FieldUpdate *) hint; if (fieldUpdate->node == node) { if (fieldUpdate->index == -1) { FieldViewItem *item = _fields[fieldUpdate->field]; FieldValue *value = node->getField(fieldUpdate->field); item->SetValue(value); if (item->IsGroup() && !item->IsCollapsed()) { if (_fieldViewActive) swInvalidateWindow(_window); } } else { MFieldValue *value = (MFieldValue *) node->getField(fieldUpdate->field); MFieldViewItem *parent = (MFieldViewItem *) _fields[fieldUpdate->field]; parent->GetChild(fieldUpdate->index)->SetValue(value->getSFValue(fieldUpdate->index)); } if (_fieldViewActive) { RefreshItemList(); GetFieldRect(fieldUpdate->field, fieldUpdate->index, &rect); swInvalidateRect(_window, rect.left, rect.top, rect.Width(), rect.Height()); } } break; case UPDATE_CHANGE_INTERFACE_NODE: UpdateAll(); case UPDATE_ADD_NODE: case UPDATE_REMOVE_NODE: nodeUpdate = (NodeUpdate *) hint; if (nodeUpdate->parent == node) { if (nodeUpdate->field) GetFieldRect(nodeUpdate->field, -1, &rect); RefreshItemList(); swInvalidateRect(_window, rect.left, rect.top, rect.Width(), rect.Height()); } break; case UPDATE_MODE: // select a field which makes sense for this mode? case UPDATE_TIME: break; } } void FieldView::UpdateAll() { int width0 = GetColumnWidth(0); int width1 = GetColumnWidth(1); /* Array collapsedNames; if (_selectedNode) { Proto *def = _selectedNode->getProto(); if (def) { for (int i = 0; i < _fields.size(); i++) if (_fields[i]->IsCollapsed() && (def->getField(i)->getName()->getlength() != 0)) collapsedNames.append(strdup(def->getField(i)->getName())); } } */ DeleteFields(); if (_selectedNode) { Proto *def = _selectedNode->getProto(); if (def) { _fields.resize(def->getNumFields()); for (int i = 0; i < _fields.size(); i++) { Field *field = def->getField(i); FieldValue *value = _selectedNode->getField(i); Rect r1; GetItemRect(i, &r1); Rect rect(width0, r1.top, width0 + width1-1, r1.bottom); _fields[i] = FieldViewItem::CreateItem(field, this); _fields[i]->SetIndex(i); _fields[i]->CreateControl(rect, _window); _fields[i]->SetValue(value); /* for (int j = 0; j < collapsedNames.size(); j++) if (strcmp(collapsedNames[j], field->getName()) == 0) _fields[i]->SetFlag(FVIS_COLLAPSED); */ } } } _isRoot = false; if (_selectedNode == _scene->getRoot()) _isRoot = true; _selectedItem = _selectedField = -1; RefreshItemList(); swInvalidateWindow(_window); } void FieldView::DrawItem(int index, SDC dc) { Proto *def = _selectedNode->getProto(); Field *field; FieldViewItem *item = _items[index]; FieldViewItem *parent = item->GetParent(); int cx = GetColumnWidth(0); Rect r; GetItemRect(index, &r); swSetClipRect(dc, 0, r.top, r.Width(), _itemHeight); if (_isRoot) return; if (parent) { // item is a MField entry field = def->getField(parent->GetIndex()); } else { field = def->getField(item->GetIndex()); parent = item; } int fg; if (item->GetState() & FVIS_SELECTED) { int highlight = swGetWindowColor(_window, SW_COLOR_HIGHLIGHT); swSetFGColor(dc, highlight); swFillRect(dc, r.left, r.top, r.Width(), r.Height()); swSetBGColor(dc, highlight); fg = swGetWindowColor(_window, SW_COLOR_HIGHLIGHT_TEXT); swSetFGColor(dc, fg); } else { int bg = swGetWindowColor(_window, SW_COLOR_WINDOW_BG); swSetFGColor(dc, bg); swFillRect(dc, r.left, r.top, r.Width(), r.Height()); swSetBGColor(dc, bg); if (parent->GetValue()) if (parent->GetValue()->equals(field->getDefault())) { fg = swGetWindowColor(_window, SW_COLOR_HIGHLIGHT); } else { fg = swGetWindowColor(_window, SW_COLOR_TEXT); } swSetFGColor(dc, fg); } swSetClipRect(dc, 0, r.top, cx, _itemHeight); if (item->IsGroup() && ((MFieldViewItem *) item)->GetNumChildren() > 0) { // draw a collapse box if (item->IsCollapsed()) { swDrawPlusBox(dc, CB_SPACING, r.top + (_itemHeight - CB_HEIGHT) / 2); } else { swDrawMinusBox(dc, CB_SPACING, r.top + (_itemHeight - CB_HEIGHT) / 2); } swSetFGColor(dc, fg); } MyString str; int x = CB_WIDTH + CB_SPACING * 2; int y = r.bottom - 2; if (item->GetParent()) { // it's an element of an MField; draw a plus sign to insert a new index int extraSpace = 0; if (item->IsCollapsed()) { extraSpace = CB_ARRAY_INSERT; swDrawPlusBox(dc, extraSpace, r.top + (_itemHeight - CB_HEIGHT) / 2); swSetFGColor(dc, fg); } // it's an element of an MField; draw the array index, right-justified char buf[128]; sprintf(buf, "[%d] ", item->GetIndex()); swDrawText(dc, x + extraSpace, y, buf); } else { // is a parent node, draw the name swDrawTextTruncated(dc, x, r.top, cx - x, r.Height() - 1, field->getName()); } swSetClipRect(dc, r.left, r.top, r.Width(), _itemHeight); item->Draw(dc, cx + 2, r.top); swSetFGColor(dc, 0x000000); swFillPatternRect(dc, 0, r.bottom, r.Width(), 1, _halftoneBitmap); swFillPatternRect(dc, cx-1, r.top, 1, r.Height(), _halftoneBitmap); } void FieldView::OnHeaderChange(int index, int width) { if (index == 0) { int w, h; swHeaderGetSize(_header, &w, &h); swHeaderSetItemWidth(_header, 0, width); swHeaderSetItemWidth(_header, 1, w - width); MoveControls(width); swInvalidateRect(_window, 0, h, w, _height); } } int FieldView::GetColumnWidth(int column) const { return swHeaderGetItemWidth(_header, column); } void FieldView::SetColumnWidth(int column, int width) { swHeaderSetItemWidth(_header, column, width); } void FieldView::MoveControls(int left) { Rect r; for (int i = 0; i < _items.size(); i++) { GetItemRect(i, &r); _items[i]->MoveControl(left, r.top); } } int FieldView::HitTest(int x, int y) { int width, height; swHeaderGetSize(_header, &width, &height); int pos = (y - height) / _itemHeight; if (pos >= 0 && pos < _items.size()) { return pos; } else { return -1; } } void FieldView::GetItemRect(int i, Rect *r) { int width, height; swGetSize(_window, &width, &height); r->top = (i+1 - _scrollY)*_itemHeight; r->bottom = r->top + _itemHeight - 1; r->left = 0; r->right = width - 1; } void FieldView::GetFieldRect(int field, int index, Rect *r) { int width, height; swHeaderGetSize(_header, &width, &height); int top = height - _scrollY * _itemHeight; for (int i = 0; i < field; i++) { if (_fields[i]->IsGroup() && !_fields[i]->IsCollapsed()) { top += (((MFieldViewItem *) _fields[i])->GetNumChildren() + 1) * _itemHeight; } else { top += _itemHeight; } } if (index == -1) { if (_fields[field]->IsGroup() && !_fields[field]->IsCollapsed()) { r->top = top; r->bottom = (((MFieldViewItem *) _fields[field])->GetNumChildren() + 1) * _itemHeight - 1; } else { r->top = top; r->bottom = top + _itemHeight - 1; } } else { r->top = top + (index+1) * _itemHeight; r->bottom = r->top + _itemHeight - 1; } r->left = 0; r->right = width - 1; } void FieldView::OnSize(int width, int height) { swSetSize(_scroller, width, height); swSetScrollSizes(_scroller, _width, height); int widthReduce = 0; if (_header) { swHeaderSetSize(_header, width, _itemHeight); widthReduce = swHeaderGetItemWidth(_header, 0); swHeaderSetItemWidth(_header, 1, width - widthReduce); } _pageHeight = height / _itemHeight; UpdateBars(); } void FieldView::UpdateBars() { static bool inUpdate = false; if (!inUpdate) { inUpdate = true; int x, y, width, height; swGetPosition(_window, &x, &y); swGetSize(_window, &width, &height); if (_height > y + height) { // SCROLLINFO info; // info.cbSize = sizeof(SCROLLINFO); // info.fMask = SIF_PAGE | SIF_RANGE; // info.nMin = 0; // if (_items.size() > 32767) { // info.nMax = 32767; _scrollRatio = _items.size() / 32767.0f; // } else { // info.nMax = _items.size(); _scrollRatio = 1.0f; // } // info.nPage = _pageHeight; // SetScrollInfo(SB_VERT, &info); if (_items.size() > _pageHeight) { // EnableScrollBarCtrl(SB_VERT, TRUE); } else { // EnableScrollBarCtrl(SB_VERT, FALSE); _scrollY = 0; } } else { // EnableScrollBarCtrl(SB_VERT, FALSE); _scrollY = 0; } inUpdate = false; } } void FieldView::StartEditing() { Rect r; int cx = GetColumnWidth(0); MyString buf; _scene->UpdateViews(this, UPDATE_START_FIELD_EDIT); FieldViewItem *item = _items[_selectedItem]; _selectedOffset = item->GetFieldOffset(_trackPoint.x - cx); GetItemRect(_selectedItem, &r); item->StartEditing(buf, _selectedOffset); #ifdef WIN32 _edit = swCreateTextEdit(SW_SINGLE_LINE, cx + _selectedOffset * _floatWidth, r.top-4, r.Width(), r.Height() + 8, _window); #else _edit = swCreateTextEdit(SW_SINGLE_LINE, cx + _selectedOffset * _floatWidth, r.top, r.Width(), r.Height(), _window); #endif swSetText(_edit, buf); swTextEditSetSelection(_edit, 0, strlen(buf)); swSetCommandCallback(_edit, textCommandCallback); swSetFocusCallback(_edit, textFocusCallback); swSetClientData(_edit, this); swSetFocus(_edit); swEnableAccelerators(FALSE); _state = EDITING; } void FieldView::StopEditing() { if (_state != EDITING) return; Node *node = _scene->getSelection()->getNode(); static FieldUpdate hint(node, _selectedField, _selectedIndex); _scene->UpdateViews(this, UPDATE_STOP_FIELD_EDIT, (Hint *) &hint); FieldValue *value = node->getField(_selectedField); FieldValue *newValue; char str[128]; _state = NORMAL; swGetText(_edit, str, 128); newValue = _items[_selectedItem]->StopEditing(str, _selectedOffset); if (newValue != NULL) { if (_items[_selectedItem]->GetParent()) { MFieldValue *mvalue = (MFieldValue *) _selectedNode->getField(_selectedField); mvalue->setSFValue(_selectedIndex, newValue); _items[_selectedItem]->SetValue(newValue); _scene->setField(_selectedNode, _selectedField, mvalue); swInvalidateWindow(_window); } else { _scene->backupField(_selectedNode, _selectedField); _scene->setField(_selectedNode, _selectedField, newValue); } } swDestroyWindow(_edit); swEnableAccelerators(TRUE); if (!_items[_selectedItem]->IsCollapsed()) RefreshItemList(); swInvalidateWindow(_window); } void FieldView::AbortEditing() { _state = NORMAL; swDestroyWindow(_edit); } void FieldView::OnLButtonDown(int x, int y, int modifiers) { y += _scrollY * _itemHeight; int hit = HitTest(x, y); Rect r; if (_state == EDITING) { StopEditing(); } else if (hit != -1) { FieldViewItem *item = _items[hit]; if (_selectedItem != hit) { // unhighlight old selection, if any if (_selectedItem != -1) { _items[_selectedItem]->ClearFlag(FVIS_SELECTED); GetItemRect(_selectedItem, &r); swInvalidateRect(_window, r.left, r.top, r.Width(), r.Height()); } // highlight new selection item->SetFlag(FVIS_SELECTED); _selectedItem = hit; GetItemRect(hit, &r); swInvalidateRect(_window, r.left, r.top, r.Width(), r.Height()); } bool colorcircle_flag=false; if (item->GetParent()) { // selected item is a child of an MField; // use the parent's field index _selectedField = item->GetParent()->GetIndex(); _selectedIndex = item->GetIndex(); _scene->setViewOfLastSelection(this); if (item->IsCollapsed() && (x > CB_ARRAY_INSERT) && (x < CB_ARRAY_INSERT + CB_WIDTH) && (_selectedNode->getField(_selectedField)->getType() != MFNODE) ) { // add to array box was picked if (item->GetParent() != NULL) { ((MFieldViewItem *)item->GetParent())->InsertItem(this, _selectedIndex + 1); _selectedNode->update(); } RefreshItemList(); // move all controls below the item toggled MoveControls(GetColumnWidth(0)); swInvalidateWindow(_window); } FieldUpdate hint(_scene->getSelection()->getNode(), _selectedField,_selectedIndex); _scene->UpdateViews(this,UPDATE_SELECTED_FIELD, (Hint *) &hint); if (_selectedNode->getField(_selectedField)->getType()==MFCOLOR) { colorcircle_flag=true; _scene->UpdateViews(this,UPDATE_ENABLE_COLOR_CIRCLE, (Hint *) &hint); } } else { // otherwise it's a SField, use its own index _selectedField = item->GetIndex(); _selectedIndex = -1; _scene->setViewOfLastSelection(this); FieldUpdate hint(_scene->getSelection()->getNode(), _selectedField); _scene->UpdateViews(this,UPDATE_SELECTED_FIELD, (Hint *) &hint); if (_selectedNode->getField(_selectedField)->getType()==SFCOLOR) { colorcircle_flag=true; _scene->UpdateViews(this,UPDATE_ENABLE_COLOR_CIRCLE, (Hint *) &hint); } } if (!colorcircle_flag) _scene->UpdateViews(this,UPDATE_DISABLE_COLOR_CIRCLE); GetItemRect(hit, &r); int width0 = GetColumnWidth(0); if (x > width0) { FieldValue *value = item->OnMouseDown(x - width0, y - r.top, 0); if (value && !value->equals(item->GetValue())) { if (item->GetParent()) { _scene->execute(new MFieldCommand(_selectedNode, _selectedField, _selectedIndex, value)); } else { _scene->execute(new FieldCommand(_selectedNode, _selectedField, value)); } } else if (item->IsEditable()) { _state = WAIT_EDIT; } else if (item->IsTrackable()) { _state = WAIT_TRACK; } else if (item->GetValue()->getType() == SFNODE) { Node *child = ((SFNode *) item->GetValue())->getValue(); if (child) { _scene->setSelection(child); _scene->UpdateViews(this, UPDATE_SELECTION); return; } } } if (item->IsGroup() && x > CB_SPACING && x < CB_SPACING + CB_WIDTH) { // collapse box was picked item->SetCollapsed(!item->IsCollapsed()); RefreshItemList(); // move all controls below the item toggled MoveControls(GetColumnWidth(0)); swInvalidateWindow(_window); } else { _trackPoint = Point(x, y); _selectedOffset = item->GetFieldOffset(x - width0); } } } // test if a mousedrag would change a value // if yes, show a cursor different from usual Arrow void FieldView::UpdateTrackingCursor(int x, int y) { bool cursorIsArrow = true; int hit=HitTest(x, y); if (hit != -1) if (_items[hit]->IsTrackable()) { Rect r; GetItemRect(hit, &r); int width0 = GetColumnWidth(0); if ((x > width0) && (x - width0 < GetItemWidth())) cursorIsArrow = false; } if ((cursorIsArrow) && (!_cursorIsArrow)) swSetCursor(_window, _cursorArrow); if ((!cursorIsArrow) && (_cursorIsArrow)) swSetCursor(_window, _cursorHMove); _cursorIsArrow = cursorIsArrow; } void FieldView::OnMouseMove(int x, int y, int modifiers) { FieldValue *newValue; if (_state == WAIT_EDIT || _state == WAIT_TRACK) { if (_items[_selectedItem]->IsTrackable()) { StartTracking(); } else { _state = NORMAL; } } UpdateTrackingCursor(x, y); if (_state == TRACKING) { FieldViewItem *item = _items[_selectedItem]; int delta = x - _trackPoint.x; newValue = item->OnMouseMove(_trackValue, _selectedOffset, delta); ChangeValue(item, newValue); } } void FieldView::ChangeValue(FieldViewItem *item, FieldValue *newValue) { assert(item && newValue); if ((!newValue->equals(item->GetValue())) || (isMFType(newValue->getType()))) { int field = _selectedField; newValue->clamp(_selectedNode->getProto()->getField(field)->getMin(), _selectedNode->getProto()->getField(field)->getMax()); int index = _selectedIndex; if (item->GetParent()) { MFieldValue *value = (MFieldValue *) _selectedNode->getField(field); value->setSFValue(_selectedIndex, newValue); item->SetValue(newValue); _scene->setField(_selectedNode, field, value); swInvalidateWindow(_window); } else if (isMFType(newValue->getType())) { // index is 0, field is collapsed index = 0; MFieldValue *value = (MFieldValue *) _selectedNode->getField(field); FieldValue *sfValue = ((MFieldValue *)newValue)->getSFValue(0); value->setSFValue(index, sfValue); ((MFieldViewItem *)item)->InitIndexValue(0, newValue); _scene->setField(_selectedNode, field, value); swInvalidateWindow(_window); } else { _scene->setField(_selectedNode, field, newValue); _fields[field]->SetValue(newValue); } FieldUpdate update(_selectedNode, field, index); _scene->UpdateViews(this, UPDATE_FIELD, (Hint *) &update); } else { delete newValue; } } void FieldView::OnLButtonUp(int x, int y, int modifiers) { if (_state == TRACKING) { StopTracking(); } else if (_state == WAIT_EDIT) { StartEditing(); } else { _state = NORMAL; } } void FieldView::StartTracking() { Command *cmd; _state = TRACKING; swSetCapture(_window); _trackValue = _items[_selectedItem]->GetValue(); _trackValue->ref(); if (_selectedIndex != -1) { cmd = new MFieldCommand(_selectedNode, _selectedField, _selectedIndex); } else { cmd = new FieldCommand(_selectedNode, _selectedField); } _scene->add(cmd); } void FieldView::StopTracking() { _state = NORMAL; swReleaseCapture(_window); _trackValue->unref(); _trackValue = NULL; } void FieldView::RefreshItemList() { int n = _fields.size(); int item = 0; _items.resize(0); for (int i = 0; i < n; i++) { _items[item++] = _fields[i]; if (_fields[i]->IsGroup() && !_fields[i]->IsCollapsed()) { MFieldViewItem *mf = (MFieldViewItem *) _fields[i]; int nc = mf->GetNumChildren(); for (int j = 0; j < nc; j++) { _items[item++] = mf->GetChild(j); mf->GetChild(j)->SetIndex(j); } } } _height = (_items.size()+1) * _itemHeight; int width, height; swGetSize(_window, &width, &height); swSetScrollSizes(_scroller, _width, _height); _pageHeight = height / _itemHeight; UpdateBars(); } void FieldView::DeleteLastSelection(void) { if (_state == NORMAL) { FieldViewItem *item = _items[_selectedItem]; MFieldViewItem *parent = (MFieldViewItem *)item->GetParent(); if (parent) { // selected item is a child of an MField; parent->RemoveItem(this, item->GetIndex()); _selectedField = -1; _selectedItem = -1; // UpdateAll(); RefreshItemList(); Node *node =_scene->getSelection()->getNode(); if (node != NULL) node->update(); // move all controls below the item toggled MoveControls(GetColumnWidth(0)); swInvalidateWindow(_window); _scene->UpdateViews(NULL, UPDATE_SELECTION); } } } /* void FieldView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { OnScroll(MAKEWORD(nSBCode, -1), nPos); } void FieldView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { int oldScrollY = _scrollY; switch (nSBCode) { case SB_TOP: _scrollY = 0; break; case SB_BOTTOM: _scrollY = _items.size() - 1 - _pageHeight; break; case SB_LINEUP: _scrollY--; break; case SB_LINEDOWN: _scrollY++; break; case SB_PAGEUP: _scrollY -= _pageHeight; break; case SB_PAGEDOWN: _scrollY += _pageHeight; if (_scrollY > _items.size() - 1 - _pageHeight) { _scrollY = _items.size() - 1 - _pageHeight; } break; case SB_THUMBTRACK: case SB_THUMBPOSITION: _scrollY = (int) (nPos * _scrollRatio); break; } _scrollY = CLAMP(_scrollY, 0, _items.size() - _pageHeight + 1); if (_scrollY != oldScrollY) { Rect r; GetClientRect(&r); SetScrollPos(SB_VERT, (int) (_scrollY / _scrollRatio)); r.top = _itemHeight; // don't scroll header ScrollWindow(0, (oldScrollY - _scrollY) * _itemHeight, r, r); UpdateWindow(); } } */