home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 275 / DPCS0111DVD.ISO / Toolkit / Audio-Visual / VirtualDub / Source / VirtualDub-1.9.10-src.7z / src / Dita / source / ctl_grid.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2009-09-14  |  9.8 KB  |  394 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2004 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include <stdafx.h>
  19. #include <vd2/Dita/basetypes.h>
  20. #include <vector>
  21.  
  22. class VDUIGrid : public VDUIWindow, public IVDUIGrid {
  23. public:
  24.     VDUIGrid();
  25.     ~VDUIGrid();
  26.  
  27.     void *AsInterface(uint32 id);
  28.  
  29.     bool Create(IVDUIParameters *pParams);
  30.     void AddChild(IVDUIWindow *pWindow);
  31.     void AddChild(IVDUIWindow *pWin, int col, int row, int colspan, int rowspan);
  32.     void RemoveChild(IVDUIWindow *pWindow);
  33.     void PreLayoutBase(const VDUILayoutSpecs&);
  34.     void PostLayoutBase(const vduirect&);
  35.  
  36.     void SetRow(int row, int minsize=-1, int maxsize=-1, int affinity=-1);
  37.     void SetColumn(int col, int minsize=-1, int maxsize=-1, int affinity=-1);
  38.     void NextRow();
  39.  
  40. protected:
  41.     int mnFillCount;
  42.     int mSpacing;
  43.  
  44.     int mX, mY;
  45.     bool mbVerticalTravel;
  46.  
  47.     class Axis {
  48.     public:
  49.         Axis();
  50.  
  51.         void Extend(int cell);
  52.         void SetBehavior(int cell, int minsize, int maxsize, int affinity);
  53.         void BeginLayout();
  54.         int GetSpanMax(int start, int end, int limit) const;
  55.         int GetSpanWidth(int start, int end) const { return mEntries[end-1].end - mEntries[start].start; }
  56.         void ApplyMinimum(int start, int end, int minval);
  57.         int GetMinimumSum() const;
  58.         int GetCount() const { return mEntries.size()-1; }
  59.         int GetStart(int i) const { return mEntries[i].start; }
  60.         int GetEnd(int i) const { return mEntries[i].end; }
  61.         void Layout(int pos, int width, int pad);
  62.  
  63.     protected:
  64.         struct Entry {
  65.             int minsize;
  66.             int maxsize;
  67.             int maxsizesum;
  68.             int affinity;
  69.             int affinitysum;
  70.             int mincursize;
  71.             int start, end;
  72.  
  73.             Entry() : minsize(0), maxsize(INT_MAX), affinity(0) {}
  74.         };
  75.  
  76.         typedef std::vector<Entry> tEntries;
  77.         tEntries    mEntries;
  78.     };
  79.  
  80.     Axis    mRows;
  81.     Axis    mCols;
  82.  
  83.     struct GridItem {
  84.         IVDUIWindow *mpWin;
  85.         vduirect    mPos;
  86.     };
  87.     typedef std::vector<GridItem> tItems;
  88.  
  89.     tItems        mItems;
  90. };
  91.  
  92. IVDUIWindow *VDCreateUIGrid() { return new VDUIGrid; }
  93.  
  94. VDUIGrid::VDUIGrid() {
  95.     mAlignX = nsVDUI::kFill;
  96.     mAlignY = nsVDUI::kFill;
  97.     mSpacing = 0;
  98.     mX = 0;
  99.     mY = 0;
  100.     mbVerticalTravel = false;
  101. }
  102.  
  103. VDUIGrid::~VDUIGrid() {
  104. }
  105.  
  106. void *VDUIGrid::AsInterface(uint32 id) {
  107.     switch(id) {
  108.     case IVDUIGrid::kTypeID: return static_cast<IVDUIGrid *>(this);
  109.     }
  110.  
  111.     return VDUIWindow::AsInterface(id);
  112. }
  113.  
  114. bool VDUIGrid::Create(IVDUIParameters *pParams) {
  115.     mSpacing = pParams->GetI(nsVDUI::kUIParam_Spacing, 0);
  116.     mbVerticalTravel = pParams->GetB(nsVDUI::kUIParam_IsVertical, false);
  117.     return VDUIWindow::Create(pParams);
  118. }
  119.  
  120. void VDUIGrid::AddChild(IVDUIWindow *pWindow) {
  121.     AddChild(pWindow, -1, -1, 1, 1);
  122. }
  123.  
  124. void VDUIGrid::AddChild(IVDUIWindow *pWin, int col, int row, int colspan, int rowspan) {
  125.     VDASSERT(rowspan>=1 && colspan>=1);
  126.  
  127.     if (col >= 0)
  128.         mX = col;
  129.  
  130.     if (row >= 0)
  131.         mY = row;
  132.  
  133.     tChildren::iterator it(std::find(mChildren.begin(), mChildren.end(), pWin));
  134.  
  135.     if (it == mChildren.end()) {
  136.         mChildren.push_back(pWin);
  137.         pWin->AddRef();
  138.         pWin->SetParent(this);
  139.  
  140.         GridItem item;
  141.         
  142.         item.mpWin = pWin;
  143.         item.mPos = vduirect(mX, mY, mX+colspan, mY+rowspan);
  144.         mItems.push_back(item);
  145.  
  146.         mCols.Extend(mX);
  147.         mRows.Extend(mY);
  148.  
  149.         if (mbVerticalTravel)
  150.             mY += rowspan;
  151.         else
  152.             mX += colspan;
  153.     }
  154. }
  155.  
  156. void VDUIGrid::RemoveChild(IVDUIWindow *pWindow) {
  157.     tItems::iterator it(mItems.begin()), itEnd(mItems.end());
  158.  
  159.     for(; it!=itEnd; ++it) {
  160.         GridItem& item = *it;
  161.  
  162.         if (item.mpWin == pWindow) {
  163.             mItems.erase(it);
  164.             pWindow->SetParent(NULL);
  165.             break;
  166.         }
  167.     }
  168.  
  169.     VDUIWindow::RemoveChild(pWindow);
  170. }
  171.  
  172. void VDUIGrid::PreLayoutBase(const VDUILayoutSpecs& parentConstraints) {
  173.     vduisize pad = mpBase->MapUnitsToPixels(vduisize(mSpacing, mSpacing));
  174.  
  175.     mLayoutSpecs.minsize.w = 0;
  176.     mLayoutSpecs.minsize.h = 0;
  177.  
  178.     const int rows = mRows.GetCount();
  179.     const int cols = mCols.GetCount();
  180.  
  181.     mRows.BeginLayout();
  182.     mCols.BeginLayout();
  183.  
  184.     // phase I: constraint gathering
  185.     tItems::const_iterator itItem(mItems.begin()), itItemEnd(mItems.end());
  186.     for(; itItem != itItemEnd; ++itItem) {
  187.         const GridItem& item = *itItem;
  188.         const vduirect& cells = item.mPos;
  189.  
  190.         VDUILayoutSpecs cellConstraints;
  191.  
  192.         cellConstraints.minsize.w = mCols.GetSpanMax(cells.left, cells.right, parentConstraints.minsize.w);
  193.         cellConstraints.minsize.h = mRows.GetSpanMax(cells.top, cells.bottom, parentConstraints.minsize.h);
  194.  
  195.         item.mpWin->PreLayout(cellConstraints);
  196.  
  197.         const VDUILayoutSpecs& specs = item.mpWin->GetLayoutSpecs();
  198.         const int minw = specs.minsize.w;
  199.         const int minh = specs.minsize.h;
  200.  
  201.         mCols.ApplyMinimum(cells.left, cells.right, minw);
  202.         mRows.ApplyMinimum(cells.top, cells.bottom, minh);
  203.     }
  204.  
  205.     mLayoutSpecs.minsize.w = pad.w*(cols-1) + mCols.GetMinimumSum();
  206.     mLayoutSpecs.minsize.h = pad.h*(rows-1) + mRows.GetMinimumSum();
  207. }
  208.  
  209. void VDUIGrid::PostLayoutBase(const vduirect& target) {
  210.     vduisize pad = mpBase->MapUnitsToPixels(vduisize(mSpacing, mSpacing));
  211.  
  212.     // phase II: layout columns
  213.     mCols.Layout(target.left, target.width(), pad.w);
  214.  
  215.     tItems::const_iterator itItem(mItems.begin()), itItemEnd(mItems.end());
  216.     for(; itItem != itItemEnd; ++itItem) {
  217.         const GridItem& item = *itItem;
  218.         const vduirect& cells = item.mPos;
  219.  
  220.         VDUILayoutSpecs cellConstraints;
  221.  
  222.         cellConstraints.minsize.w = mCols.GetSpanWidth(cells.left, cells.right);
  223.         cellConstraints.minsize.h = target.height();
  224.  
  225.         item.mpWin->PreLayout(cellConstraints);
  226.  
  227.         const VDUILayoutSpecs& specs = item.mpWin->GetLayoutSpecs();
  228.         const int minh = specs.minsize.h;
  229.  
  230.         mRows.ApplyMinimum(cells.top, cells.bottom, minh);
  231.     }
  232.  
  233.     // phase III: final layout
  234.     mRows.Layout(target.top, target.height(), pad.h);
  235.  
  236.     itItem = mItems.begin();
  237.     itItemEnd = mItems.end();
  238.     for(; itItem != itItemEnd; ++itItem) {
  239.         const GridItem& item = *itItem;
  240.         const vduirect& cells = item.mPos;
  241.  
  242.         item.mpWin->PostLayout(vduirect(mCols.GetStart(cells.left), mRows.GetStart(cells.top), mCols.GetEnd(cells.right-1), mRows.GetEnd(cells.bottom-1)));
  243.     }
  244. }
  245.  
  246. void VDUIGrid::SetRow(int row, int minsize, int maxsize, int affinity) {
  247.     mRows.SetBehavior(row, minsize, maxsize, affinity);
  248. }
  249.  
  250. void VDUIGrid::SetColumn(int col, int minsize, int maxsize, int affinity) {
  251.     mCols.SetBehavior(col, minsize, maxsize, affinity);
  252. }
  253.  
  254. void VDUIGrid::NextRow() {
  255.     if (mbVerticalTravel) {
  256.         ++mX;
  257.         mY = 0;
  258.     } else {
  259.         ++mY;
  260.         mX = 0;
  261.     }
  262. }
  263.  
  264. ///////////////////////////////////////////////////////////////////////////
  265.  
  266. VDUIGrid::Axis::Axis() {
  267.     Extend(0);
  268. }
  269.  
  270. void VDUIGrid::Axis::Extend(int cell) {
  271.     VDASSERT(cell >= 0);
  272.  
  273.     if ((size_t)(cell+1) >= mEntries.size())        // need sentinel at end too
  274.         mEntries.resize(cell+2);
  275. }
  276.  
  277. void VDUIGrid::Axis::SetBehavior(int cell, int minsize, int maxsize, int affinity) {
  278.     Extend(cell);
  279.  
  280.     Entry& ent = mEntries[cell];
  281.  
  282.     if (minsize >= 0)
  283.         ent.minsize = minsize;
  284.  
  285.     if (maxsize >= 0)
  286.         ent.maxsize = maxsize;
  287.  
  288.     if (ent.maxsize < ent.minsize)
  289.         ent.maxsize = ent.minsize;
  290.  
  291.     if (affinity >= 0)
  292.         ent.affinity = affinity;
  293. }
  294.  
  295. void VDUIGrid::Axis::BeginLayout() {
  296.     tEntries::iterator it(mEntries.begin()), itEnd(mEntries.end());
  297.  
  298.     int affinitysum = 0;
  299.     int maxsizesum = 0;
  300.     for(; it!=itEnd; ++it) {
  301.         Entry& ent = *it;
  302.  
  303.         ent.mincursize = ent.minsize;
  304.         ent.affinitysum = affinitysum;
  305.         ent.maxsizesum = maxsizesum;
  306.         affinitysum += ent.affinity;
  307.  
  308.         if (ent.maxsize == INT_MAX)
  309.             ++maxsizesum;
  310.         else
  311.             maxsizesum += ent.maxsize << 12;
  312.     }
  313. }
  314.  
  315. int VDUIGrid::Axis::GetSpanMax(int start, int end, int limit) const {
  316.     VDASSERT(start >= 0);
  317.     VDASSERT((size_t)end < mEntries.size());
  318.  
  319.     int diff = mEntries[end].maxsizesum - mEntries[start].maxsizesum;
  320.  
  321.     if (diff & 0xfff)
  322.         return limit;
  323.  
  324.     diff >>= 12;
  325.  
  326.     if (diff > limit)
  327.         diff = limit;
  328.  
  329.     return diff;
  330. }
  331.  
  332. void VDUIGrid::Axis::ApplyMinimum(int start, int end, int minval) {
  333.     VDASSERT(start >= 0);
  334.     VDASSERT((size_t)end < mEntries.size());
  335.  
  336.     // fast path
  337.     if (end == start+1) {
  338.         int& curmin = mEntries[start].mincursize;
  339.  
  340.         if (curmin < minval)
  341.             curmin = minval;
  342.  
  343.         return;
  344.     }
  345.  
  346.     const int affsum = mEntries[end].affinitysum - mEntries[start].affinitysum;
  347.     int affleft = affsum ? affsum : end-start;
  348.  
  349.     for(int i=start; i<end; ++i) {
  350.         Entry& ent = mEntries[i];
  351.         int affinity = affsum ? ent.affinity : 1;
  352.         int minslice = affinity ? (minval * affinity + affleft - 1) / affleft : 0;
  353.  
  354.         if (ent.mincursize < minslice)
  355.             ent.mincursize = minslice;
  356.  
  357.         minval -= minslice;
  358.     }
  359. }
  360.  
  361. int VDUIGrid::Axis::GetMinimumSum() const {
  362.     const int ents = mEntries.size();
  363.     int sum = 0;
  364.  
  365.     for(int i=0; i<ents-1; ++i)
  366.         sum += mEntries[i].mincursize;
  367.  
  368.     return sum;
  369. }
  370.  
  371. void VDUIGrid::Axis::Layout(int pos, int width, int pad) {
  372.     const int n = mEntries.size() - 1;
  373.     const int affsum = mEntries[n].affinitysum - mEntries[0].affinitysum;
  374.     int affleft = affsum ? affsum : n;
  375.     int slackleft = width - pad*(n-1) - GetMinimumSum();
  376.  
  377.     if (slackleft < 0)
  378.         slackleft = 0;
  379.  
  380.     for(int i=0; i<n; ++i) {
  381.         Entry& ent = mEntries[i];
  382.         const int affinity = affsum ? ent.affinity : 1;
  383.         const int minslice = affinity ? (slackleft * affinity + affleft - 1) / affleft : 0;
  384.  
  385.         ent.start = pos;
  386.         pos += ent.mincursize + minslice;
  387.         ent.end = pos;
  388.         pos += pad;
  389.  
  390.         affleft -= affinity;
  391.         slackleft -= minslice;
  392.     }
  393. }
  394.