Index: ui/uilib/static_ex.cc |
diff --git a/ui/uilib/static_ex.cc b/ui/uilib/static_ex.cc |
deleted file mode 100644 |
index c038f65f8d84f74bd431a18e12448f645af59fec..0000000000000000000000000000000000000000 |
--- a/ui/uilib/static_ex.cc |
+++ /dev/null |
@@ -1,586 +0,0 @@ |
-// Copyright 2006-2009 Google Inc. |
-// |
-// Licensed under the Apache License, Version 2.0 (the "License"); |
-// you may not use this file except in compliance with the License. |
-// You may obtain a copy of the License at |
-// |
-// http://www.apache.org/licenses/LICENSE-2.0 |
-// |
-// Unless required by applicable law or agreed to in writing, software |
-// distributed under the License is distributed on an "AS IS" BASIS, |
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
-// See the License for the specific language governing permissions and |
-// limitations under the License. |
-// ======================================================================== |
-// |
- |
-// TODO(omaha): need to handle WM_GETTEXT |
-// TODO(omaha): need to handle WM_SIZE |
-// TODO(omaha): nice to have transparent mode |
- |
-#include "omaha/ui/uilib/static_ex.h" |
- |
-#include <shellapi.h> |
-#include <strsafe.h> |
-#include "omaha/ui/uilib/node_state.h" |
- |
-const int StaticEx::kBorderNone = 0; |
-const int StaticEx::kBorderLeft = 1; |
-const int StaticEx::kBorderTop = 2; |
-const int StaticEx::kBorderRight = 4; |
-const int StaticEx::kBorderBottom = 8; |
-const int StaticEx::kBorderAll = kBorderLeft | kBorderTop | kBorderRight | |
- kBorderBottom; |
- |
-HCURSOR StaticEx::hand_cursor_ = NULL; |
- |
-StaticEx::StaticEx() |
- : margins_(1, 0, 1, 0), // see comment in h file |
- background_color_(0xffffff), |
- use_background_color_(false), |
- ellipsis_(0), |
- border_(kBorderNone), |
- border_color_(0), |
- default_font_(NULL) { |
-} |
- |
-StaticEx::~StaticEx() { |
- EraseNodes(); |
- EraseLines(&lines_); |
-} |
- |
-void StaticEx::Reset() { |
- text_.Empty(); |
- EraseNodes(); |
- EraseLines(&lines_); |
- default_font_ = NULL; |
-} |
- |
-BOOL StaticEx::SubclassWindow(HWND window) { |
- Reset(); |
- // first get text from exising control |
- unsigned length = ::SendMessage(window, WM_GETTEXTLENGTH, 0, 0); |
- CString text; |
- if (length > 0) { |
- TCHAR* buffer = text.GetBufferSetLength(length); |
- ::SendMessage(window, |
- WM_GETTEXT, |
- length + 1, |
- reinterpret_cast<LPARAM>(buffer)); |
- text.ReleaseBuffer(-1); |
- } |
- |
- // then subclass |
- BOOL result = CWindowImpl<StaticEx>::SubclassWindow(window); |
- |
- // set text back (it will parse it and replace text in subclassed control |
- // with readble text) |
- if (result && length > 0) { |
- SetWindowText(text); |
- } |
- |
- return result; |
-} |
- |
-HWND StaticEx::UnsubclassWindow(BOOL force /*= FALSE*/) { |
- Reset(); // clean up an old state |
- return CWindowImpl<StaticEx>::UnsubclassWindow(force); |
-} |
- |
-LRESULT StaticEx::OnSetText(UINT msg, WPARAM wparam, LPARAM lparam, |
- BOOL& handled) { |
- // parse text first, because we will need to get "readable" text |
- text_ = reinterpret_cast<const TCHAR*>(lparam); |
- ParseText(); |
- |
- // set readable text to subclassed control, this text will be return by |
- // GetWindowText() or WM_GETTEXT. (when GetWindowText is called from another |
- // process it doesn't send WM_GETTEXT but reads text directly from contol) |
- // so we need to set text to it. |
- // Disable redraw, without it calling DefWindowProc would redraw control |
- // immediately without sending WM_PAINT message |
- SetRedraw(FALSE); |
- DefWindowProc(msg, wparam, |
- reinterpret_cast<LPARAM>(static_cast<const TCHAR*>(GetReadableText()))); |
- SetRedraw(TRUE); |
- |
- // now invalidate to display new text |
- Invalidate(); |
- |
- handled = TRUE; |
- return 1; |
-} |
- |
-LRESULT StaticEx::OnGetText(UINT, WPARAM wparam, LPARAM lparam, BOOL& handled) { // NOLINT |
- if (!lparam) return 0; |
- unsigned size = static_cast<unsigned>(wparam); |
- TCHAR* buffer = reinterpret_cast<TCHAR*>(lparam); |
- |
- handled = TRUE; |
- unsigned my_size = text_.GetLength(); |
- if (my_size < size) { |
- StringCchCopy(buffer, size, text_); |
- return my_size; |
- } |
- |
- StringCchCopyN(buffer, size, text_, size - 1); |
- buffer[size - 1] = 0; |
- |
- return size - 1; |
-} |
- |
-LRESULT StaticEx::OnGetTextLength(UINT, WPARAM, LPARAM, BOOL& handled) { // NOLINT |
- handled = TRUE; |
- return text_.GetLength(); |
-} |
- |
-void StaticEx::set_background_color(COLORREF back_color) { |
- background_color_ = back_color; |
- use_background_color_ = true; |
- Invalidate(); |
-} |
- |
-void StaticEx::set_margins(const RECT& rect) { |
- margins_ = rect; |
- Invalidate(); |
-} |
- |
-void StaticEx::set_margins(int left, int top, int right, int bottom) { |
- margins_.SetRect(left, top, right, bottom); |
- Invalidate(); |
-} |
- |
- |
-LRESULT StaticEx::OnLButtonUp(UINT, WPARAM, LPARAM lparam, BOOL&) { |
- CPoint point(LOWORD(lparam), HIWORD(lparam)); |
- |
- int height = margins_.top + (border_ & kBorderTop) ? 1 : 0; |
- size_t size = lines_.size(); |
- for (size_t i = 0; i < size; i++) { |
- height += lines_[i]->height(); |
- if (point.y < height) { |
- CString action; |
- if (lines_[i]->IsUrlUnderMouse(point, &action) && !action.IsEmpty()) { |
- // Notify the parent window to handle the click. |
- LRESULT handled = 0; |
- NMSTATICEX notification = {0}; |
- notification.header.hwndFrom = m_hWnd; |
- notification.header.idFrom = GetDlgCtrlID(); |
- notification.header.code = NM_STATICEX; |
- notification.action = action; |
- |
- HWND parent = GetParent(); |
- if (parent) { |
- handled = ::SendMessage(parent, WM_NOTIFY, notification.header.idFrom, |
- reinterpret_cast<LPARAM>(¬ification)); |
- ATLASSERT(handled); |
- } |
- } |
- break; |
- } |
- } |
- return 0; |
-} |
- |
- |
-LRESULT StaticEx::OnSetCursor(UINT, WPARAM, LPARAM lparam, BOOL& handled) { // NOLINT |
- int hit_test = LOWORD(lparam); |
- handled = FALSE; |
- if (hit_test != HTCLIENT) { |
- return 0; |
- } |
- |
- POINT position; |
- if (!GetCursorPos(&position)) |
- return 0; |
- |
- ScreenToClient(&position); |
- |
- int offset = margins_.top + (border_ & kBorderTop) ? 1 : 0; |
- size_t size = lines_.size(); |
- for (size_t i = 0; i < size; i++) { |
- offset += lines_[i]->height(); |
- if (position.y < offset) { |
- if (lines_[i]->IsUrlUnderMouse(position, NULL)) { |
- ::SetCursor(GetHandCursor()); |
- handled = TRUE; |
- } |
- break; |
- } |
- } |
- |
- return 0; |
-} |
- |
-void StaticEx::set_ellipsis(int ellipsis) { |
- if (ellipsis == DT_END_ELLIPSIS || |
- ellipsis == DT_WORD_ELLIPSIS || |
- ellipsis == DT_PATH_ELLIPSIS || |
- ellipsis == 0) { |
- ellipsis_ = ellipsis; |
- if (ellipsis != 0) |
- ModifyStyle(0, SS_LEFTNOWORDWRAP); |
- Invalidate(); |
- } |
-} |
- |
-void StaticEx::set_border(int border) { |
- border_ = border; |
- Invalidate(); |
-} |
- |
-void StaticEx::set_border_color(COLORREF border_color) { |
- border_color_ = border_color; |
- Invalidate(); |
-} |
- |
-void StaticEx::ParseText() { |
- EraseNodes(); |
- EraseLines(&lines_); |
- |
- if (text_.IsEmpty()) |
- return; |
- |
- if (!default_font_) |
- default_font_ = GetFont(); |
- |
- NodeState node_state(m_hWnd); |
- node_state.SetStdFont(default_font_); |
- |
- const TCHAR* current_string = text_; |
- int current_offset = 0; |
- bool had_good_tag = true; |
- while (*current_string) { |
- current_offset = 0; |
- |
- if (had_good_tag) { |
- // if it was a good tag we consumed it and need to start with a new node |
- Node* node = new Node(m_hWnd); |
- nodes_.push_back(node); |
- |
- // -1 if there is no Open Bracket "<" |
- current_offset = FindOpenBracket(current_string); |
- |
- if (current_offset < 0) { |
- // no tags left, just plain text |
- node->AddText(current_string); |
- node->set_node_state(node_state); |
- break; |
- } |
- |
- if (*current_string != _T('<')) { |
- // has some text before the tag |
- node->AddText(CString(current_string, current_offset)); |
- node->set_node_state(node_state); |
- current_string += current_offset; |
- continue; |
- } |
- |
- int next_offset = node_state.ConsumeTag(current_string + current_offset); |
- |
- if (next_offset > 0) { |
- // it was a known tag |
- had_good_tag = true; |
- current_string += current_offset + next_offset; |
- } else { |
- // unknown tag, will keep looking |
- had_good_tag = false; |
- node->AddText(CString(current_string, current_offset + 1)); |
- node->set_node_state(node_state); |
- current_string += current_offset + 1; |
- continue; |
- } |
- } else { |
- had_good_tag = true; |
- } |
- delete nodes_.back(); |
- nodes_.pop_back(); |
- } |
-} |
- |
-CString StaticEx::GetReadableText() { |
- CString text; |
- for (size_t i = 0; i < nodes_.size(); i++) { |
- text += nodes_[i]->node_text(); |
- } |
- return text; |
-} |
- |
-void StaticEx::EraseNodes() { |
- for (size_t i = 0; i < nodes_.size(); ++i) { |
- delete nodes_[i]; |
- } |
- nodes_.clear(); |
-} |
- |
-void StaticEx::EraseLines(std::vector<StaticLine*>* lines) { |
- size_t size = lines->size(); |
- for (size_t i = 0; i < size; i++) { |
- delete (*lines)[i]; |
- } |
- lines->clear(); |
-} |
- |
-int StaticEx::FindOpenBracket(const TCHAR* string) { |
- const TCHAR* left_bracket = _tcschr(string, _T('<')); |
- |
- if (left_bracket == NULL) |
- return -1; |
- |
- return static_cast<int>(left_bracket - string); |
-} |
- |
-LRESULT StaticEx::OnPaint(UINT, WPARAM, LPARAM, BOOL&) { |
- PAINTSTRUCT paint_struct; |
- HDC hdc = BeginPaint(&paint_struct); |
- |
- CRect client_rect; |
- GetClientRect(&client_rect); |
- |
- CRect working_rect(client_rect); |
- |
- working_rect.DeflateRect(margins_); |
- working_rect.DeflateRect((border_ & kBorderLeft) ? 1 : 0, |
- (border_ & kBorderTop) ? 1 : 0, |
- (border_ & kBorderRight) ? 1 : 0, |
- (border_ & kBorderBottom) ? 1 : 0); |
- |
- DWORD style = GetStyle(); |
- |
- EraseLines(&lines_); |
- PrePaint(hdc, &lines_, nodes_, working_rect, style, ellipsis_); |
- |
- if (use_background_color_) { |
- FillRect(hdc, &client_rect, CreateSolidBrush(background_color_)); |
- } else { |
- HBRUSH brush = reinterpret_cast<HBRUSH>(::SendMessage(GetParent(), |
- WM_CTLCOLORSTATIC, reinterpret_cast<WPARAM>(hdc), |
- reinterpret_cast<LPARAM>(m_hWnd))); |
- if (brush) { |
- ::FillRect(hdc, &client_rect, brush); |
- } |
- } |
- |
- if (border_ != kBorderNone) |
- DrawBorder(hdc, client_rect); |
- |
- Paint(hdc, lines_, working_rect, style, ellipsis_); |
- |
- EndPaint(&paint_struct); |
- return 0; |
-} |
- |
-void StaticEx::PrePaint(HDC hdc, std::vector<StaticLine*>* lines, |
- const std::vector<Node*>& nodes, RECT rect, DWORD style, |
- int ellipsis) { |
- if (nodes.empty()) |
- return; |
- |
- int x = 0; |
- int width = rect.right - rect.left; |
- StaticLine* line = new StaticLine; |
- lines->push_back(line); |
- bool done = false; |
- size_t size = nodes.size(); |
- for (size_t i = 0; i < size; ++i) { |
- Node* node = nodes[i]; |
- const NodeState& node_state = node->node_state(); |
- CString text = node->node_text(); |
- int string_len = text.GetLength(); |
- |
- HFONT font = node_state.GetFont(); |
- if (!font) |
- return; |
- |
- HFONT old_font = static_cast<HFONT>(SelectObject(hdc, font)); |
- |
- TEXTMETRIC text_metrics; |
- GetTextMetrics(hdc, &text_metrics); |
- |
- int height = text_metrics.tmHeight + text_metrics.tmExternalLeading; |
- int base_line = text_metrics.tmHeight + text_metrics.tmExternalLeading - |
- text_metrics.tmDescent; |
- line->AdjustHeight(height); |
- line->AdjustBaseLine(base_line); |
- |
- bool single_line = (style & SS_LEFTNOWORDWRAP) != 0; |
- |
- int current_pos = 0; |
- bool more_left = false; |
- while (true) { |
- int current_length = string_len - current_pos; |
- |
- // find LF if any |
- int lf_position = text.Find(_T('\n'), current_pos); |
- if (lf_position == current_pos) { |
- if (single_line) { |
- if (ellipsis) |
- line->AddEllipses(); |
- break; |
- } |
- line = new StaticLine; |
- lines->push_back(line); |
- line->AdjustHeight(height); |
- line->AdjustBaseLine(base_line); |
- x = 0; |
- |
- current_pos++; |
- |
- continue; |
- } else if (lf_position > 0) { |
- current_length = lf_position - current_pos; |
- more_left = true; |
- } |
- |
- // check if it will fit in one line |
- int fit = 0; |
- SIZE string_size; |
- GetTextExtentExPoint(hdc, static_cast<const TCHAR*>(text) + current_pos, |
- current_length, width - x, &fit, NULL, &string_size); |
- |
- if (fit < current_length) { |
- // string doesn't fit, need to move to the next line |
- // find last space |
- int fit_saved = fit; |
- for (; fit > 0; fit--) { |
- if (text.GetAt(current_pos + fit) == _T(' ')) { |
- break; |
- } |
- } |
- |
- // if a first word of a node doesn't fit and it starts in a first half |
- // of control then wrap the word on a last char that fits |
- // otherwise move whole node to the next line |
- if ((fit <= 0) && (x < width / 2)) |
- fit = fit_saved; |
- |
- if (fit > 0) { |
- line->AddNode(node, current_pos, fit, height, base_line, width - x); |
- } |
- |
- if (single_line) { |
- if (ellipsis) |
- line->AddEllipses(); |
- done = true; |
- break; |
- } |
- line = new StaticLine; |
- lines->push_back(line); |
- line->AdjustHeight(height); |
- line->AdjustBaseLine(base_line); |
- x = 0; |
- |
- current_pos += fit; |
- // skip spaces |
- while (text.GetAt(current_pos) == _T(' ')) |
- current_pos++; |
- continue; |
- } else { |
- line->AddNode(node, current_pos, fit, height, base_line, |
- string_size.cx); |
- } |
- |
- // done, it fits |
- x += string_size.cx; |
- if (!more_left) |
- break; |
- |
- current_pos += current_length; |
- more_left = false; |
- } |
- |
- if (old_font) |
- SelectObject(hdc, old_font); |
- |
- if (done) |
- break; |
- } |
-} |
- |
- |
-void StaticEx::Paint(HDC hdc, const std::vector<StaticLine*>& lines, RECT rect, |
- DWORD style, int ellipsis) { |
- if ((style & SS_LEFTNOWORDWRAP) == 0) { |
- ellipsis = 0; |
- } |
- |
- size_t size = lines.size(); |
- int y = rect.top; |
- for (size_t i = 0; i < size; i++) { |
- int height = lines[i]->Paint(hdc, rect.left, rect.right, y, style, |
- ellipsis); |
- y += height; |
- } |
-} |
- |
-LRESULT StaticEx::OnEraseBkgnd(UINT /*msg*/, WPARAM /*wparam*/, |
- LPARAM /*lparam*/, BOOL& handled) { |
- handled = TRUE; |
- return 0; |
-} |
- |
-void StaticEx::DrawBorder(HDC hdc, const CRect& rect) { |
- HGDIOBJ old_object = SelectObject(hdc, GetStockObject(DC_PEN)); |
- SetDCPenColor(hdc, border_color_); |
- if (border_ & kBorderLeft) { |
- MoveToEx(hdc, rect.left, rect.top, NULL); |
- LineTo(hdc, rect.left, rect.bottom); |
- } |
- if (border_ & kBorderTop) { |
- MoveToEx(hdc, rect.left, rect.top, NULL); |
- LineTo(hdc, rect.right, rect.top); |
- } |
- if (border_ & kBorderRight) { |
- MoveToEx(hdc, rect.right - 1, rect.top, NULL); |
- LineTo(hdc, rect.right - 1, rect.bottom); |
- } |
- if (border_ & kBorderBottom) { |
- MoveToEx(hdc, rect.left, rect.bottom - 1, NULL); |
- LineTo(hdc, rect.right, rect.bottom - 1); |
- } |
- SelectObject(hdc, old_object); |
-} |
- |
-int StaticEx::GetMinimumHeight(int width) { |
- HDC device_context = CreateCompatibleDC(NULL); |
- |
- CRect client_rect; |
- if (width <= 0) |
- GetClientRect(&client_rect); |
- else |
- client_rect.SetRect(0, 0, width, 100); // last value is not used |
- |
- CRect working_rect(client_rect); |
- |
- working_rect.DeflateRect(margins_); |
- working_rect.DeflateRect((border_ & kBorderLeft) ? 1 : 0, |
- (border_ & kBorderTop) ? 1 : 0, |
- (border_ & kBorderRight) ? 1 : 0, |
- (border_ & kBorderBottom) ? 1 : 0); |
- |
- DWORD style = GetStyle(); |
- |
- std::vector<StaticLine*> lines; |
- PrePaint(device_context, &lines, nodes_, working_rect, style, ellipsis_); |
- |
- DeleteDC(device_context); |
- |
- int height = 0; |
- for (unsigned i = 0; i < lines.size(); i++) { |
- height += lines[i]->height(); |
- } |
- height += margins_.top + margins_.bottom; |
- height += (border_ & kBorderTop) ? 1 : 0; |
- height += (border_ & kBorderBottom) ? 1 : 0; |
- |
- return height; |
-} |
- |
- |
-HCURSOR StaticEx::GetHandCursor() { |
- if (hand_cursor_ == NULL) { |
- // Load cursor resource |
- hand_cursor_ = (HCURSOR)LoadCursor(NULL, IDC_HAND); // doesn't work on NT4! |
- } |
- return hand_cursor_; |
-} |