PageRenderTime 41ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llui/llscrolllistcolumn.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 336 lines | 237 code | 44 blank | 55 comment | 46 complexity | e4cfc0fcc7dfc30049270525ae96276c MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llscrollcolumnheader.cpp
  3. * @brief Scroll lists are composed of rows (items), each of which
  4. * contains columns (cells).
  5. *
  6. * $LicenseInfo:firstyear=2007&license=viewerlgpl$
  7. * Second Life Viewer Source Code
  8. * Copyright (C) 2010, Linden Research, Inc.
  9. *
  10. * This library is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU Lesser General Public
  12. * License as published by the Free Software Foundation;
  13. * version 2.1 of the License only.
  14. *
  15. * This library is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * Lesser General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public
  21. * License along with this library; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23. *
  24. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  25. * $/LicenseInfo$
  26. */
  27. #include "linden_common.h"
  28. #include "llscrolllistcolumn.h"
  29. #include "llbutton.h"
  30. #include "llresizebar.h"
  31. #include "llscrolllistcell.h"
  32. #include "llscrolllistctrl.h"
  33. #include "llscrolllistitem.h"
  34. #include "lluictrlfactory.h"
  35. const S32 MIN_COLUMN_WIDTH = 20;
  36. // defaults for LLScrollColumnHeader param block pulled from widgets/scroll_column_header.xml
  37. static LLWidgetNameRegistry::StaticRegistrar sRegisterColumnHeaderParams(&typeid(LLScrollColumnHeader::Params), "scroll_column_header");
  38. //---------------------------------------------------------------------------
  39. // LLScrollColumnHeader
  40. //---------------------------------------------------------------------------
  41. LLScrollColumnHeader::Params::Params()
  42. : column("column")
  43. {}
  44. LLScrollColumnHeader::LLScrollColumnHeader(const LLScrollColumnHeader::Params& p)
  45. : LLButton(p), // use combobox params to steal images
  46. mColumn(p.column),
  47. mHasResizableElement(FALSE)
  48. {
  49. setClickedCallback(boost::bind(&LLScrollColumnHeader::onClick, this, _2));
  50. // resize handles on left and right
  51. const S32 RESIZE_BAR_THICKNESS = 3;
  52. LLResizeBar::Params resize_bar_p;
  53. resize_bar_p.resizing_view(this);
  54. resize_bar_p.rect(LLRect(getRect().getWidth() - RESIZE_BAR_THICKNESS, getRect().getHeight(), getRect().getWidth(), 0));
  55. resize_bar_p.min_size(MIN_COLUMN_WIDTH);
  56. resize_bar_p.side(LLResizeBar::RIGHT);
  57. resize_bar_p.enabled(false);
  58. mResizeBar = LLUICtrlFactory::create<LLResizeBar>(resize_bar_p);
  59. addChild(mResizeBar);
  60. }
  61. LLScrollColumnHeader::~LLScrollColumnHeader()
  62. {}
  63. void LLScrollColumnHeader::draw()
  64. {
  65. std::string sort_column = mColumn->mParentCtrl->getSortColumnName();
  66. BOOL draw_arrow = !mColumn->mLabel.empty()
  67. && mColumn->mParentCtrl->isSorted()
  68. // check for indirect sorting column as well as column's sorting name
  69. && (sort_column == mColumn->mSortingColumn || sort_column == mColumn->mName);
  70. BOOL is_ascending = mColumn->mParentCtrl->getSortAscending();
  71. if (draw_arrow)
  72. {
  73. setImageOverlay(is_ascending ? "up_arrow.tga" : "down_arrow.tga", LLFontGL::RIGHT, LLColor4::white);
  74. }
  75. else
  76. {
  77. setImageOverlay(LLUUID::null);
  78. }
  79. // Draw children
  80. LLButton::draw();
  81. }
  82. BOOL LLScrollColumnHeader::handleDoubleClick(S32 x, S32 y, MASK mask)
  83. {
  84. if (canResize() && mResizeBar->getRect().pointInRect(x, y))
  85. {
  86. // reshape column to max content width
  87. LLRect column_rect = getRect();
  88. column_rect.mRight = column_rect.mLeft + mColumn->mMaxContentWidth;
  89. setShape(column_rect, true);
  90. }
  91. else
  92. {
  93. onClick(LLSD());
  94. }
  95. return TRUE;
  96. }
  97. void LLScrollColumnHeader::onClick(const LLSD& data)
  98. {
  99. if (mColumn)
  100. {
  101. LLScrollListCtrl::onClickColumn(mColumn);
  102. }
  103. }
  104. LLView* LLScrollColumnHeader::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding)
  105. {
  106. // this logic assumes dragging on right
  107. llassert(snap_edge == SNAP_RIGHT);
  108. // use higher snap threshold for column headers
  109. threshold = llmin(threshold, 10);
  110. LLRect snap_rect = getSnapRect();
  111. S32 snap_delta = mColumn->mMaxContentWidth - snap_rect.getWidth();
  112. // x coord growing means column growing, so same signs mean we're going in right direction
  113. if (llabs(snap_delta) <= threshold && mouse_dir.mX * snap_delta > 0 )
  114. {
  115. new_edge_val = snap_rect.mRight + snap_delta;
  116. }
  117. else
  118. {
  119. LLScrollListColumn* next_column = mColumn->mParentCtrl->getColumn(mColumn->mIndex + 1);
  120. while (next_column)
  121. {
  122. if (next_column->mHeader)
  123. {
  124. snap_delta = (next_column->mHeader->getSnapRect().mRight - next_column->mMaxContentWidth) - snap_rect.mRight;
  125. if (llabs(snap_delta) <= threshold && mouse_dir.mX * snap_delta > 0 )
  126. {
  127. new_edge_val = snap_rect.mRight + snap_delta;
  128. }
  129. break;
  130. }
  131. next_column = mColumn->mParentCtrl->getColumn(next_column->mIndex + 1);
  132. }
  133. }
  134. return this;
  135. }
  136. void LLScrollColumnHeader::handleReshape(const LLRect& new_rect, bool by_user)
  137. {
  138. S32 new_width = new_rect.getWidth();
  139. S32 delta_width = new_width - (getRect().getWidth() /*+ mColumn->mParentCtrl->getColumnPadding()*/);
  140. if (delta_width != 0)
  141. {
  142. S32 remaining_width = -delta_width;
  143. S32 col;
  144. for (col = mColumn->mIndex + 1; col < mColumn->mParentCtrl->getNumColumns(); col++)
  145. {
  146. LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
  147. if (!columnp) continue;
  148. if (columnp->mHeader && columnp->mHeader->canResize())
  149. {
  150. // how many pixels in width can this column afford to give up?
  151. S32 resize_buffer_amt = llmax(0, columnp->getWidth() - MIN_COLUMN_WIDTH);
  152. // user shrinking column, need to add width to other columns
  153. if (delta_width < 0)
  154. {
  155. if (columnp->getWidth() > 0)
  156. {
  157. // statically sized column, give all remaining width to this column
  158. columnp->setWidth(columnp->getWidth() + remaining_width);
  159. if (columnp->mRelWidth > 0.f)
  160. {
  161. columnp->mRelWidth = (F32)columnp->getWidth() / (F32)mColumn->mParentCtrl->getItemListRect().getWidth();
  162. }
  163. // all padding went to this widget, we're done
  164. break;
  165. }
  166. }
  167. else
  168. {
  169. // user growing column, need to take width from other columns
  170. remaining_width += resize_buffer_amt;
  171. if (columnp->getWidth() > 0)
  172. {
  173. columnp->setWidth(columnp->getWidth() - llmin(columnp->getWidth() - MIN_COLUMN_WIDTH, delta_width));
  174. if (columnp->mRelWidth > 0.f)
  175. {
  176. columnp->mRelWidth = (F32)columnp->getWidth() / (F32)mColumn->mParentCtrl->getItemListRect().getWidth();
  177. }
  178. }
  179. if (remaining_width >= 0)
  180. {
  181. // width sucked up from neighboring columns, done
  182. break;
  183. }
  184. }
  185. }
  186. }
  187. // clamp resize amount to maximum that can be absorbed by other columns
  188. if (delta_width > 0)
  189. {
  190. delta_width += llmin(remaining_width, 0);
  191. }
  192. // propagate constrained delta_width to new width for this column
  193. new_width = getRect().getWidth() + delta_width - mColumn->mParentCtrl->getColumnPadding();
  194. // use requested width
  195. mColumn->setWidth(new_width);
  196. // update proportional spacing
  197. if (mColumn->mRelWidth > 0.f)
  198. {
  199. mColumn->mRelWidth = (F32)new_width / (F32)mColumn->mParentCtrl->getItemListRect().getWidth();
  200. }
  201. // tell scroll list to layout columns again
  202. // do immediate update to get proper feedback to resize handle
  203. // which needs to know how far the resize actually went
  204. mColumn->mParentCtrl->updateColumns();
  205. }
  206. }
  207. void LLScrollColumnHeader::setHasResizableElement(BOOL resizable)
  208. {
  209. if (mHasResizableElement != resizable)
  210. {
  211. mColumn->mParentCtrl->dirtyColumns();
  212. mHasResizableElement = resizable;
  213. }
  214. }
  215. void LLScrollColumnHeader::updateResizeBars()
  216. {
  217. S32 num_resizable_columns = 0;
  218. S32 col;
  219. for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++)
  220. {
  221. LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
  222. if (columnp->mHeader && columnp->mHeader->canResize())
  223. {
  224. num_resizable_columns++;
  225. }
  226. }
  227. S32 num_resizers_enabled = 0;
  228. // now enable/disable resize handles on resizable columns if we have at least two
  229. for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++)
  230. {
  231. LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
  232. if (!columnp->mHeader) continue;
  233. BOOL enable = num_resizable_columns >= 2 && num_resizers_enabled < (num_resizable_columns - 1) && columnp->mHeader->canResize();
  234. columnp->mHeader->enableResizeBar(enable);
  235. if (enable)
  236. {
  237. num_resizers_enabled++;
  238. }
  239. }
  240. }
  241. void LLScrollColumnHeader::enableResizeBar(BOOL enable)
  242. {
  243. mResizeBar->setEnabled(enable);
  244. }
  245. BOOL LLScrollColumnHeader::canResize()
  246. {
  247. return getVisible() && (mHasResizableElement || mColumn->mDynamicWidth);
  248. }
  249. void LLScrollListColumn::SortNames::declareValues()
  250. {
  251. declare("ascending", LLScrollListColumn::ASCENDING);
  252. declare("descending", LLScrollListColumn::DESCENDING);
  253. }
  254. //
  255. // LLScrollListColumn
  256. //
  257. //static
  258. const LLScrollListColumn::Params& LLScrollListColumn::getDefaultParams()
  259. {
  260. return LLUICtrlFactory::getDefaultParams<LLScrollListColumn>();
  261. }
  262. LLScrollListColumn::LLScrollListColumn(const Params& p, LLScrollListCtrl* parent)
  263. : mWidth(0),
  264. mIndex (-1),
  265. mParentCtrl(parent),
  266. mName(p.name),
  267. mLabel(p.header.label),
  268. mHeader(NULL),
  269. mMaxContentWidth(0),
  270. mDynamicWidth(p.width.dynamic_width),
  271. mRelWidth(p.width.relative_width),
  272. mFontAlignment(p.halign),
  273. mSortingColumn(p.sort_column)
  274. {
  275. if (p.sort_ascending.isProvided())
  276. {
  277. mSortDirection = p.sort_ascending() ? ASCENDING : DESCENDING;
  278. }
  279. else
  280. {
  281. mSortDirection = p.sort_direction;
  282. }
  283. setWidth(p.width.pixel_width);
  284. }
  285. void LLScrollListColumn::setWidth(S32 width)
  286. {
  287. if (!mDynamicWidth && mRelWidth <= 0.f)
  288. {
  289. mParentCtrl->updateStaticColumnWidth(this, width);
  290. }
  291. mWidth = width;
  292. }