1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ui/views/examples/multiline_example.h"
6
7#include "base/strings/utf_string_conversions.h"
8#include "ui/events/event.h"
9#include "ui/gfx/render_text.h"
10#include "ui/views/background.h"
11#include "ui/views/border.h"
12#include "ui/views/controls/button/checkbox.h"
13#include "ui/views/controls/label.h"
14#include "ui/views/controls/textfield/textfield.h"
15#include "ui/views/layout/grid_layout.h"
16#include "ui/views/view.h"
17
18using base::ASCIIToUTF16;
19
20namespace views {
21namespace examples {
22
23namespace {
24
25gfx::Range ClampRange(gfx::Range range, size_t max) {
26  range.set_start(std::min(range.start(), max));
27  range.set_end(std::min(range.end(), max));
28  return range;
29}
30
31// A Label with a clamped preferred width to demonstrate wrapping.
32class PreferredSizeLabel : public Label {
33 public:
34  PreferredSizeLabel() : Label() {}
35  virtual ~PreferredSizeLabel() {}
36
37  // Label:
38  virtual gfx::Size GetPreferredSize() const OVERRIDE {
39    return gfx::Size(50, Label::GetPreferredSize().height());
40  }
41
42 private:
43  DISALLOW_COPY_AND_ASSIGN(PreferredSizeLabel);
44};
45
46}  // namespace
47
48// A simple View that hosts a RenderText object.
49class MultilineExample::RenderTextView : public View {
50 public:
51  RenderTextView() : render_text_(gfx::RenderText::CreateInstance()) {
52    render_text_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
53    render_text_->SetColor(SK_ColorBLACK);
54    render_text_->SetMultiline(true);
55    SetBorder(Border::CreateSolidBorder(2, SK_ColorGRAY));
56  }
57
58  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
59    View::OnPaint(canvas);
60    render_text_->Draw(canvas);
61  }
62
63  virtual gfx::Size GetPreferredSize() const OVERRIDE {
64    // Turn off multiline mode to get the single-line text size, which is the
65    // preferred size for this view.
66    render_text_->SetMultiline(false);
67    gfx::Size size(render_text_->GetContentWidth(),
68                   render_text_->GetStringSize().height());
69    size.Enlarge(GetInsets().width(), GetInsets().height());
70    render_text_->SetMultiline(true);
71    return size;
72  }
73
74  virtual int GetHeightForWidth(int w) const OVERRIDE {
75    // TODO(ckocagil): Why does this happen?
76    if (w == 0)
77      return View::GetHeightForWidth(w);
78    const gfx::Rect old_rect = render_text_->display_rect();
79    gfx::Rect rect = old_rect;
80    rect.set_width(w - GetInsets().width());
81    render_text_->SetDisplayRect(rect);
82    int height = render_text_->GetStringSize().height() + GetInsets().height();
83    render_text_->SetDisplayRect(old_rect);
84    return height;
85  }
86
87  void SetText(const base::string16& new_contents) {
88    // Color and style the text inside |test_range| to test colors and styles.
89    const size_t range_max = new_contents.length();
90    gfx::Range color_range = ClampRange(gfx::Range(1, 21), range_max);
91    gfx::Range bold_range = ClampRange(gfx::Range(4, 10), range_max);
92    gfx::Range italic_range = ClampRange(gfx::Range(7, 13), range_max);
93
94    render_text_->SetText(new_contents);
95    render_text_->SetColor(SK_ColorBLACK);
96    render_text_->ApplyColor(0xFFFF0000, color_range);
97    render_text_->SetStyle(gfx::DIAGONAL_STRIKE, false);
98    render_text_->ApplyStyle(gfx::DIAGONAL_STRIKE, true, color_range);
99    render_text_->SetStyle(gfx::UNDERLINE, false);
100    render_text_->ApplyStyle(gfx::UNDERLINE, true, color_range);
101    render_text_->ApplyStyle(gfx::BOLD, true, bold_range);
102    render_text_->ApplyStyle(gfx::ITALIC, true, italic_range);
103    InvalidateLayout();
104  }
105
106 private:
107  virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE {
108    gfx::Rect bounds = GetLocalBounds();
109    bounds.Inset(GetInsets());
110    render_text_->SetDisplayRect(bounds);
111  }
112
113  scoped_ptr<gfx::RenderText> render_text_;
114
115  DISALLOW_COPY_AND_ASSIGN(RenderTextView);
116};
117
118MultilineExample::MultilineExample()
119    : ExampleBase("Multiline RenderText"),
120      render_text_view_(NULL),
121      label_(NULL),
122      textfield_(NULL),
123      label_checkbox_(NULL) {
124}
125
126MultilineExample::~MultilineExample() {
127}
128
129void MultilineExample::CreateExampleView(View* container) {
130  const base::string16 kTestString = base::WideToUTF16(L"qwerty"
131      L"\x627\x644\x631\x626\x64A\x633\x64A\x629"
132      L"asdfgh");
133
134  render_text_view_ = new RenderTextView();
135  render_text_view_->SetText(kTestString);
136
137  label_ = new PreferredSizeLabel();
138  label_->SetText(kTestString);
139  label_->SetMultiLine(true);
140  label_->SetBorder(Border::CreateSolidBorder(2, SK_ColorCYAN));
141
142  label_checkbox_ = new Checkbox(ASCIIToUTF16("views::Label:"));
143  label_checkbox_->SetChecked(true);
144  label_checkbox_->set_listener(this);
145  label_checkbox_->set_request_focus_on_press(false);
146
147  textfield_ = new Textfield();
148  textfield_->set_controller(this);
149  textfield_->SetText(kTestString);
150
151  GridLayout* layout = new GridLayout(container);
152  container->SetLayoutManager(layout);
153
154  ColumnSet* column_set = layout->AddColumnSet(0);
155  column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
156      0.0f, GridLayout::USE_PREF, 0, 0);
157  column_set->AddColumn(GridLayout::FILL, GridLayout::FILL,
158      1.0f, GridLayout::FIXED, 0, 0);
159
160  layout->StartRow(0, 0);
161  layout->AddView(new Label(ASCIIToUTF16("gfx::RenderText:")));
162  layout->AddView(render_text_view_);
163
164  layout->StartRow(0, 0);
165  layout->AddView(label_checkbox_);
166  layout->AddView(label_);
167
168  layout->StartRow(0, 0);
169  layout->AddView(new Label(ASCIIToUTF16("Sample Text:")));
170  layout->AddView(textfield_);
171}
172
173void MultilineExample::ContentsChanged(Textfield* sender,
174                                       const base::string16& new_contents) {
175  render_text_view_->SetText(new_contents);
176  if (label_checkbox_->checked())
177    label_->SetText(new_contents);
178  container()->Layout();
179  container()->SchedulePaint();
180}
181
182void MultilineExample::ButtonPressed(Button* sender, const ui::Event& event) {
183  DCHECK_EQ(sender, label_checkbox_);
184  label_->SetText(label_checkbox_->checked() ? textfield_->text() :
185                                               base::string16());
186  container()->Layout();
187  container()->SchedulePaint();
188}
189
190}  // namespace examples
191}  // namespace views
192