NCBI C++ ToolKit
map_item.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: map_item.cpp 40274 2018-01-19 17:05:09Z katargir $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Andrey Yazhuk
27  *
28  */
29 
30 #include <ncbi_pch.hpp>
31 
32 #include <corelib/ncbistd.hpp>
33 
37 
38 #include <gui/utils/command.hpp>
39 
40 #include <wx/dc.h>
41 
42 #if defined(NCBI_OS_DARWIN)
43 // include Cocoa header here
44 #endif
45 
46 
48 
49 
50 ///////////////////////////////////////////////////////////////////////////////
51 /// CMapItem
52 
54 :
55  m_Separator(false),
56  m_Cmd(eCmdInvalid),
57  m_CmdTarget(NULL)
58 {
59  x_Init();
60 }
61 
62 CMapItem::CMapItem(const string& label, wxBitmap& image, const string& descr, bool separator)
63 : m_Label(label),
64  m_Icon(image),
65  m_Descr(descr),
66  m_Separator(separator),
67  m_Cmd(eCmdInvalid),
68  m_CmdTarget(NULL)
69 {
70  x_Init();
71 }
72 
73 
75 {
76 }
77 
78 
80 {
81  m_PrefsDirty = true;
82  m_LabelPrefH = 0;
83 }
84 
85 void CMapItem::SetIcon(wxBitmap& image)
86 {
87  m_Icon = image;
88  m_PrefsDirty = true;
89 }
90 
91 
92 void CMapItem::SetCommand(TCmdID cmd, wxEvtHandler* target)
93 {
94  m_Cmd = cmd;
95  m_CmdTarget = target;
96 }
97 
98 
99 static const int kSeparatorH = 9;
100 static const int kSepHorzOffset = 2;
101 static const int kSepVertOffset = 2;
102 
103 static const int kDefIconWidth = 16;
104 static const int kDefIconHeight = 16;
105 
106 
107 // Layout internal areas based on the current m_Rect
109 {
110  int i_width = kDefIconWidth;
111  int i_height = kDefIconHeight;
112 
113  // safeguard against carbon-specific issues
114  try {
115  if(m_Icon.Ok()) {
116  i_width = m_Icon.GetWidth();
117  i_height = m_Icon.GetHeight();
118  }
119  }
120  catch(std::exception&)
121  {
122  _TRACE("CMapItem::Layout - unable to determine icon size (platform has no support)");
123  }
124 
125  if(m_PrefsDirty) {
126  x_UpdatePreferredHeights(dc, props, m_Rect.width);
127  }
128 
129  wxRect rc_back(m_Rect);
130  //rc_back.Inflate(-props.m_HorzMargin, -props.m_VertMargin);
131  rc_back.Inflate(-props.m_Border, -props.m_Border);
132  int x = rc_back.GetLeft() + x_GetItemShift();
133  int y = rc_back.GetTop() + props.m_VertMargin + (m_Separator ? x_PreferredSeparatorHeight(dc) : 0);
134 
135  m_IconPos = wxPoint(0, 0); // default
136  m_LabelRect = wxRect(0, 0, -1, -1); // default
137 
138  int h1 = std::max(i_height, m_LabelPrefH);
139  bool center = props.m_CenterLabelAndIcon;
140 
141  if(m_Icon.Ok()) {
142  m_IconPos.x = x + props.m_HorzMargin;
143  int icon_off_y = center ? ((h1 - i_height) / 2) : 0;
144  m_IconPos.y = y + icon_off_y;
145  x += i_width + props.m_HorzMargin; // shift position to the right
146  }
147  // Labels
148  if( ! m_Label.empty() && x < m_Rect.GetRight()) {
149  // calculate the rectangle that will accomodate both Label and Description
150  int label_off_y = center ? ((h1 - m_LabelPrefH) / 2) : 0;
151  wxRect rc_text(x, y + label_off_y, 0, rc_back.height);
152  rc_text.SetRight(rc_back.GetRight());
153  rc_text.Inflate(-props.m_HorzMargin, 0);
154 
155  m_LabelRect = rc_text;
156  m_LabelRect.height = std::min(rc_text.height, m_LabelPrefH);
157  }
158 }
159 
160 // return horizontal shift of the item in pixels
162 {
163  return 0;
164 }
165 
166 
167 // calculates the space available for text output based on the given full item width
169 {
170  int w = width - 2 * (props.m_Border + props.m_HorzMargin);
171  if(m_Icon.Ok()) {
172  w -= m_Icon.GetWidth() + 2 * props.m_HorzMargin;
173  }
174  return std::max(0, w);
175 }
176 
177 
178 // calculates preferred text heights based on the given full item width
180 {
181  int text_w = x_GetTextAreaWidth(props, width);
182  m_LabelPrefH = x_PreferredLabelHeight(dc, props, text_w);
183  m_PrefsDirty = false;
184 }
185 
186 
187 int CMapItem::PreferredHeight(wxDC& dc, SwxMapItemProperties& props, int width)
188 {
189  if(m_PrefsDirty) {
190  x_UpdatePreferredHeights(dc, props, width);
191  }
192 
193  int icon_h = m_Icon.Ok() ? m_Icon.GetHeight() : 0;
194  int pref_h = 0;
195 
196  if(props.m_CenterLabelAndIcon) {
197  pref_h = std::max(icon_h, m_LabelPrefH);
198  } else {
199  int text_h = m_LabelPrefH;
200  pref_h = max(icon_h, text_h);
201  }
202 
203  pref_h += (props.m_Border + props.m_VertMargin) * 2;
204  if(m_Separator) {
205  pref_h += x_PreferredSeparatorHeight(dc);
206  }
207  return pref_h;
208 }
209 
210 
212 {
213  return kSeparatorH;
214 }
215 
216 
217 int CMapItem::x_PreferredLabelHeight(wxDC& dc, SwxMapItemProperties& props, int text_w) const
218 {
219  int label_h = 0;
220  if(m_Label.size()) {
221  dc.SetFont(props.m_Font);
222 
223  vector<int> line_lens;
224  WrapText(dc, m_Label, text_w, line_lens);
225 
226  label_h = (int)(line_lens.size() * abs(props.m_Font.GetPixelSize().y));
227  if(label_h > 0) {
228  label_h += 2 * props.m_VertMargin;
229  }
230  }
231  return label_h;
232 }
233 
234 
236 {
237  string text = m_Label;
238  wxRect rc = m_LabelRect;
239  int max_w = 0;
240 
241  int y = rc.GetTop() + props.m_VertMargin;
242  int text_bottom = rc.GetBottom() - props.m_VertMargin;;
243 
244  int d_h = abs(dc.GetFont().GetPixelSize().y);
245  int w = rc.GetWidth()- 2 * props.m_HorzMargin;
246 
247  // wrap text
248  vector<int> line_lens;
249  WrapText(dc, text, w, line_lens);
250 
251  int max_lines = max(0, rc.GetHeight() / d_h);
252  max_lines = min(max_lines, (int) line_lens.size());
253 
254  y -= d_h / 5;
255  bool text_truncated = (max_lines < (int) line_lens.size());
256  int pos = 0;
257  for( int i = 0; i < max_lines && y + d_h < text_bottom; i++ ) {
258  int len = line_lens[i]; // line length in chars
259  const char* line_s = text.c_str() + pos; // line text
260 
261  bool last_line = (y + 2 * d_h > text_bottom);
262  wxString wx_text;
263  if(text_truncated && last_line) {
264  wxString wx_s = ToWxString(line_s, len);
265  wx_text = TruncateText(dc, wx_s, w, ewxTruncate_EllipsisAlways);
266  } else {
267  wx_text = ToWxString(line_s, len);
268  }
269  wxSize size = dc.GetTextExtent(wx_text);
270  max_w = std::max(max_w, size.x);
271 
272  y += d_h;
273  pos += len;
274  }
275  return max_w + 2 * props.m_HorzMargin;
276 }
277 
278 
280 {
281  return m_Separator;
282 }
283 
284 
285 void CMapItem::SetRect(const wxRect& rc)
286 {
287  m_Rect = rc;
288 }
289 
290 
291 void CMapItem::GetRect(wxRect& rc) const
292 {
293  rc = m_Rect;
294 }
295 
296 
297 void CMapItem::Draw(wxDC& dc, int state, SwxMapItemProperties& props)
298 {
299  wxRect rc_back(m_Rect);
300  //rc_back.Inflate(-props.m_HorzMargin , -props.m_VertMargin);
301  rc_back.Inflate(-props.m_Border, -props.m_Border);
302 
303  // draw focus rectangle
304  x_DrawFocusRect(dc, m_Rect, state, props);
305 
306  // Fill background
307  x_DrawBackground(dc, rc_back, state, props);
308 
309  bool selected = (state & CSelectionControl::fItemSelected) != 0;
310 
311  // Draw separator
312  if(m_Separator) {
313  wxRect rc_sep(rc_back);
314  rc_sep.SetHeight(kSeparatorH);
315  x_DrawSeparator(dc, rc_sep, props);
316  }
317 
318  // Draw Icon
319  if(m_Icon.Ok()) {
320  dc.DrawBitmap(m_Icon, m_IconPos.x, m_IconPos.y, true);
321  }
322 
323  // draw the Label
324  if( ! m_Label.empty() && m_LabelRect.width > 0 && m_LabelRect.height > 0) {
325  bool widget_focused = (state & CSelectionControl::fWidgetFocused) != 0;
326 
327  if(selected) {
328  // draw background
329  dc.SetPen(*wxTRANSPARENT_PEN);
330  wxBrush brush(props.m_SelBackColor);
331  dc.SetBrush(brush);
332  wxRect rc_sel(m_LabelRect);
333  dc.DrawRectangle(rc_sel.x, rc_sel.y, rc_sel.width, rc_sel.height);
334  }
335 
336  dc.SetFont(props.m_Font);
337  x_DrawText(dc, m_Label, m_LabelRect, selected, widget_focused, false, props);
338  }
339 }
340 
341 
342 void CMapItem::x_DrawFocusRect(wxDC& dc, const wxRect& rc, int state, SwxMapItemProperties& props)
343 {
345  const wxBrush& old_brush = dc.GetBrush();
346  wxBrush brush(props.m_TextColor, wxBRUSHSTYLE_STIPPLE);
347  dc.SetBrush(brush);
348  dc.DrawRectangle(m_Rect.x, m_Rect.y, m_Rect.width, m_Rect.height);
349  dc.SetBrush(old_brush);
350  }
351 }
352 
353 
354 void CMapItem::x_DrawBackground(wxDC& dc, const wxRect& rc, int state, SwxMapItemProperties& props)
355 {
356 #if defined(NCBI_OS_DARWIN) & 0
357  //! TODO Draw theme-compliant background for the item
358  /*
359  Rect bounds;
360  SetRect (&bounds, rc_back.Left(), rc_back.Top(),
361  rc_back.Right(), rc_back.Bottom());
362  DrawThemePlacard(&bounds, kThemeStateActive);
363  */
364 #else
365  wxBrush brush( props.m_BackColor );
366  dc.SetBrush(brush);
367  dc.DrawRectangle( rc.x, rc.y, rc.width, rc.height );
368 #endif
369 }
370 
371 
372 void CMapItem::x_DrawSeparator(wxDC& dc, const wxRect& rc, SwxMapItemProperties& props)
373 {
374  wxColour sep_color = GetAverage(props.m_BackColor, props.m_TextColor, 0.5);
375  wxPen pen(sep_color);
376  dc.SetPen(pen);
377 
378  int y_line = rc.GetTop() + kSepVertOffset;
379  int left = rc.GetLeft() + kSepHorzOffset;
380  int right = rc.GetRight() - kSepHorzOffset;
381 
382  // draw 3 horizontal lines
383  dc.DrawLine(left, y_line, right, y_line);
384  y_line += 2;
385  dc.DrawLine(left, y_line, right, y_line);
386  y_line += 2;
387  dc.DrawLine(left, y_line, right, y_line);
388 }
389 
390 
391 void CMapItem::x_DrawText(wxDC& dc, const string& text, const wxRect& rc,
392  bool selected, bool focused, bool highlighted, SwxMapItemProperties& props)
393 {
394  const int x_off = props.m_HorzMargin;
395  int x = rc.GetLeft() + x_off;
396  int y = rc.GetTop() + props.m_VertMargin;
397  int text_bottom = rc.GetBottom() - props.m_VertMargin;
398 
399  int d_h = abs(dc.GetFont().GetPixelSize().y);
400 
401  int w = rc.GetWidth()- 2 * x_off;
402 
403  // wrap text
404  vector<int> line_lens;
405  WrapText(dc, text, w, line_lens);
406 
407  int max_lines = max(0, rc.GetHeight() / d_h);
408  max_lines = min(max_lines, (int) line_lens.size());
409  //int height = max_lines * d_h;
410 
411  wxColour color_text = props.m_TextColor;
412  if (selected && focused)
413  color_text = props.m_SelTextColor;
414  else if (highlighted) {
415  color_text = props.m_HiTextColor;
416  dc.SetPen(wxPen(props.m_HiTextColor, 1));
417  }
418 
419  dc.SetTextForeground(color_text);
420 
421  y -= d_h / 5;
422  bool text_truncated = (max_lines < (int) line_lens.size());
423  int pos = 0;
424  for( int i = 0; i < max_lines && y + d_h < text_bottom; i++ ) {
425  int len = line_lens[i]; // line length in chars
426  const char* line_s = text.c_str() + pos; // line text
427 
428  bool last_line = (y + 2 * d_h > text_bottom);
429  wxString wx_s = ToWxString(line_s, len);
430  if(text_truncated && last_line) {
431  wx_s = TruncateText(dc, wx_s, w, ewxTruncate_EllipsisAlways);
432  }
433  dc.DrawText(wx_s, x, y);
434 
435  if (highlighted) {
436  wxCoord w, h;
437  dc.GetTextExtent(wx_s, &w, &h);
438  dc.DrawLine(x, y + h - 1, x + w - 1, y + h - 1);
439  }
440 
441  y += d_h;
442  pos += len;
443  }
444 
445  if (highlighted)
446  dc.SetPen(*wxTRANSPARENT_PEN);
447 }
448 
449 
451 {
452 }
453 
#define false
Definition: bool.h:36
virtual void SetCommand(TCmdID cmd, wxEvtHandler *target)
enables sending commands on default action; set target to NULL to disable
Definition: map_item.cpp:92
void SetIcon(wxBitmap &image)
Definition: map_item.cpp:85
wxPoint m_IconPos
Definition: map_item.hpp:113
wxBitmap m_Icon
Definition: map_item.hpp:101
bool m_PrefsDirty
Definition: map_item.hpp:109
virtual void Layout(wxDC &dc, SwxMapItemProperties &props)
Definition: map_item.cpp:108
virtual bool IsGroupSeparator() const
Definition: map_item.cpp:279
virtual int x_PreferredSeparatorHeight(wxDC &dc) const
Definition: map_item.cpp:211
virtual int PreferredHeight(wxDC &dc, SwxMapItemProperties &props, int width)
Definition: map_item.cpp:187
virtual void x_DrawFocusRect(wxDC &dc, const wxRect &rc, int state, SwxMapItemProperties &props)
Definition: map_item.cpp:342
virtual void x_DrawText(wxDC &dc, const string &text, const wxRect &rc, bool selected, bool focused, bool highlighted, SwxMapItemProperties &props)
Definition: map_item.cpp:391
virtual void GetRect(wxRect &rc) const
Definition: map_item.cpp:291
virtual void x_DrawBackground(wxDC &dc, const wxRect &rc, int state, SwxMapItemProperties &props)
Definition: map_item.cpp:354
virtual int x_PreferredLabelHeight(wxDC &dc, SwxMapItemProperties &props, int text_w) const
Definition: map_item.cpp:217
virtual void Draw(wxDC &dc, int state, SwxMapItemProperties &props)
Draws item in the given rectangle, state is a combination of EItemState flags.
Definition: map_item.cpp:297
virtual ~CMapItem()
Definition: map_item.cpp:74
int m_LabelPrefH
Definition: map_item.hpp:110
virtual void OnDefaultAction()
a callback to perform a default action associated with the item
Definition: map_item.cpp:450
void x_Init()
Definition: map_item.cpp:79
bool m_Separator
Definition: map_item.hpp:103
wxEvtHandler * m_CmdTarget
Definition: map_item.hpp:106
virtual int x_GetItemShift() const
Definition: map_item.cpp:161
CMapItem()
CMapItem.
Definition: map_item.cpp:53
virtual void x_UpdatePreferredHeights(wxDC &dc, SwxMapItemProperties &props, int width)
Definition: map_item.cpp:179
wxRect m_Rect
Definition: map_item.hpp:112
virtual void SetRect(const wxRect &rc)
Definition: map_item.cpp:285
virtual int x_CalculateRealTextWidth(wxDC &dc, SwxMapItemProperties &props)
Definition: map_item.cpp:235
virtual void x_DrawSeparator(wxDC &dc, const wxRect &rc, SwxMapItemProperties &props)
Definition: map_item.cpp:372
wxRect m_LabelRect
Definition: map_item.hpp:114
virtual int x_GetTextAreaWidth(SwxMapItemProperties &props, int width) const
Definition: map_item.cpp:168
TCmdID m_Cmd
Definition: map_item.hpp:105
string m_Label
Definition: map_item.hpp:100
GUI command routing and handling framework.
Include a standard set of the NCBI C++ Toolkit most basic headers.
static CS_COMMAND * cmd
Definition: ct_dynamic.c:26
#define NULL
Definition: ncbistd.hpp:225
#define _TRACE(message)
Definition: ncbidbg.hpp:122
int TCmdID
@ eCmdInvalid
marks menu end in array initializers
Definition: command.hpp:64
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
static const char label[]
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
int i
int len
static const int kSepHorzOffset
Definition: map_item.cpp:100
static const int kDefIconWidth
Definition: map_item.cpp:103
static const int kSeparatorH
Definition: map_item.cpp:99
static const int kSepVertOffset
Definition: map_item.cpp:101
static const int kDefIconHeight
Definition: map_item.cpp:104
static void text(MDB_val *v)
Definition: mdb_dump.c:62
const struct ncbi::grid::netcache::search::fields::SIZE size
#define abs(a)
Definition: ncbi_heapmgr.c:130
T max(T x_, T y_)
T min(T x_, T y_)
SwxMapItemProperties - properties of the IwxMapItem.
Definition: imap_item.hpp:82
wxColour m_SelTextColor
Definition: imap_item.hpp:85
wxColour m_SelBackColor
Definition: imap_item.hpp:86
wxColour m_HiTextColor
Definition: imap_item.hpp:87
wxString ToWxString(const string &s)
Definition: wx_utils.hpp:173
wxString TruncateText(wxDC &dc, const wxString &s, int w, Ewx_Truncate trunc=ewxTruncate_Ellipsis)
truncates given string so that its length is less or equal "w" "trunc" controls truncation,...
Definition: wx_utils.cpp:878
@ ewxTruncate_EllipsisAlways
truncate text if needed, add "..." if truncated
Definition: wx_utils.hpp:226
void WrapText(wxDC &dc, const string &text, int w, vector< int > &line_lens)
divides given "text" into lines, so that every line has width less or equal to "w".
Definition: wx_utils.cpp:895
wxColour GetAverage(const wxColor &c1, const wxColor &c2, double ratio)
Definition: wx_utils.cpp:810
Modified on Tue Dec 05 02:13:59 2023 by modify_doxy.py rev. 669887