Logo Search packages:      
Sourcecode: whitedune version File versions  Download package

FieldView.cpp

/*
 * 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<MyString> 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();
    }
}
*/

Generated by  Doxygen 1.6.0   Back to index