blob: 1c74dd9737fa6c5f89c37f89563c6fbf0d35356c [file] [log] [blame]
// Copyright 2010-2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "renderer/unix/infolist_window.h"
#include "base/logging.h"
#include "base/mutex.h"
#include "renderer/renderer_command.pb.h"
#include "renderer/renderer_style.pb.h"
#include "renderer/renderer_style_handler.h"
#include "renderer/unix/cairo_wrapper.h"
#include "renderer/unix/const.h"
#include "renderer/unix/draw_tool.h"
#include "renderer/unix/font_spec.h"
#include "renderer/unix/text_renderer.h"
namespace mozc {
namespace renderer {
namespace gtk {
using mozc::commands::Candidates;
using mozc::commands::Information;
using mozc::commands::InformationList;
using mozc::commands::Output;
using mozc::commands::SessionCommand;
using mozc::renderer::RendererStyle;
using mozc::renderer::RendererStyleHandler;
namespace {
RGBA StyleColorToRGBA(const RendererStyle::RGBAColor &rgbacolor) {
const RGBA rgba = { static_cast<uint8>(rgbacolor.r()),
static_cast<uint8>(rgbacolor.g()),
static_cast<uint8>(rgbacolor.b()),
0xFF };
return rgba;
}
} // namespace
InfolistWindow::InfolistWindow(
TextRendererInterface *text_renderer,
DrawToolInterface *draw_tool,
GtkWrapperInterface *gtk,
CairoFactoryInterface *cairo_factory)
: GtkWindowBase(gtk),
text_renderer_(text_renderer),
style_(new RendererStyle()),
draw_tool_(draw_tool),
cairo_factory_(cairo_factory) {
mozc::renderer::RendererStyleHandler::GetRendererStyle(style_.get());
}
Size InfolistWindow::Update(const commands::Candidates &candidates) {
candidates_.CopyFrom(candidates);
const RendererStyle::InfolistStyle &infostyle = style_->infolist_style();
const InformationList &usages = candidates_.usages();
int ypos = infostyle.window_border();
ypos += infostyle.caption_height();
for (int i = 0; i < usages.information_size(); ++i) {
ypos += GetRowRects(i, ypos).whole_rect.Height();
}
ypos += infostyle.window_border();
const Size result_size(style_->infolist_style().window_width(), ypos);
Resize(result_size);
Redraw();
return result_size;
}
// We do not use this function. So following code makes no sense.
Rect InfolistWindow::GetCandidateColumnInClientCord() const {
DCHECK(false) << "Do not call this function without CandidateWindow.";
return Rect(0, 0, 0, 0);
}
bool InfolistWindow::OnPaint(GtkWidget *widget, GdkEventExpose *event) {
draw_tool_->Reset(cairo_factory_->CreateCairoInstance(
GetCanvasWidget()->window));
Draw();
return true;
}
int InfolistWindow::DrawCaption() {
const RendererStyle::InfolistStyle &infostyle = style_->infolist_style();
if (!infostyle.has_caption_string()) {
return 0;
}
const RendererStyle::TextStyle &caption_style = infostyle.caption_style();
const int caption_height = infostyle.caption_height();
const Rect background_rect(
infostyle.window_border(),
infostyle.window_border(),
infostyle.window_width() - infostyle.window_border() * 2,
caption_height);
const RGBA bgcolor = StyleColorToRGBA(infostyle.caption_background_color());
draw_tool_->FillRect(background_rect, bgcolor);
const Rect caption_rect(
background_rect.Left()
+ infostyle.caption_padding() + caption_style.left_padding(),
background_rect.Top() + infostyle.caption_padding(),
background_rect.Width()
- infostyle.caption_padding() - caption_style.left_padding(),
caption_height - infostyle.caption_padding());
text_renderer_->RenderText(infostyle.caption_string(), caption_rect,
FontSpec::FONTSET_INFOLIST_CAPTION);
return infostyle.caption_height();
}
void InfolistWindow::DrawFrame(int height) {
const RendererStyle::InfolistStyle &infostyle = style_->infolist_style();
const Rect rect(0, 0, infostyle.window_width(), height);
const RGBA framecolor = StyleColorToRGBA(infostyle.border_color());
draw_tool_->FrameRect(rect, framecolor, 1);
}
void InfolistWindow::Draw() {
const RendererStyle::InfolistStyle &infostyle = style_->infolist_style();
const InformationList &usages = candidates_.usages();
int ypos = infostyle.window_border();
ypos += DrawCaption();
for (int i = 0; i < usages.information_size(); ++i) {
ypos += DrawRow(i, ypos);
}
DrawFrame(ypos);
}
void InfolistWindow::GetRenderingRects(
const renderer::RendererStyle::TextStyle &style,
const string &text,
FontSpec::FONT_TYPE font_type,
int top,
Rect *background_rect,
Rect *textarea_rect) {
const RendererStyle::InfolistStyle &infostyle = style_->infolist_style();
const int text_width = infostyle.window_width()
- style.left_padding() - style.right_padding()
- infostyle.window_border() * 2 - infostyle.row_rect_padding() * 2;
const Size text_size = text_renderer_->GetMultiLinePixelSize(font_type,
text,
text_width);
background_rect->origin.x = infostyle.window_border();
background_rect->origin.y = top;
background_rect->size.width =
infostyle.window_width() - infostyle.window_border() * 2;
background_rect->size.height =
text_size.height + infostyle.row_rect_padding() * 2;
*textarea_rect = *background_rect;
textarea_rect->origin.x +=
infostyle.row_rect_padding() + style.left_padding();
textarea_rect->origin.y += infostyle.row_rect_padding();
textarea_rect->size.width = text_width;
textarea_rect->size.height = text_size.height;
}
InfolistWindow::RenderingRowRects InfolistWindow::GetRowRects(int row,
int ypos) {
const RendererStyle::InfolistStyle &infostyle = style_->infolist_style();
const InformationList &usages = candidates_.usages();
const RendererStyle::TextStyle &title_style = infostyle.title_style();
const RendererStyle::TextStyle &desc_style = infostyle.description_style();
DCHECK_GT(usages.information_size(), row);
const Information &info = usages.information(row);
RenderingRowRects result;
GetRenderingRects(title_style,
info.title(),
FontSpec::FONTSET_INFOLIST_TITLE,
ypos,
&result.title_back_rect,
&result.title_rect);
ypos += result.title_back_rect.size.height;
GetRenderingRects(desc_style,
info.description(),
FontSpec::FONTSET_INFOLIST_DESCRIPTION,
ypos,
&result.desc_back_rect,
&result.desc_rect);
result.whole_rect = result.title_back_rect;
result.whole_rect.size.height += result.desc_back_rect.Height();
return result;
}
int InfolistWindow::DrawRow(int row, int ypos) {
const RendererStyle::InfolistStyle &infostyle = style_->infolist_style();
const InformationList &usages = candidates_.usages();
const RendererStyle::TextStyle &title_style = infostyle.title_style();
const RendererStyle::TextStyle &desc_style = infostyle.description_style();
DCHECK_GT(usages.information_size(), row);
const Information &info = usages.information(row);
const RenderingRowRects row_rects = GetRowRects(row, ypos);
if (usages.has_focused_index() && (row == usages.focused_index())) {
const RGBA bgcol = StyleColorToRGBA(infostyle.focused_background_color());
draw_tool_->FillRect(row_rects.whole_rect, bgcol);
const RGBA frcol = StyleColorToRGBA(infostyle.focused_border_color());
draw_tool_->FrameRect(row_rects.whole_rect, frcol, 1);
} else {
if (title_style.has_background_color()) {
draw_tool_->FillRect(row_rects.title_back_rect,
StyleColorToRGBA(title_style.background_color()));
} else {
draw_tool_->FillRect(row_rects.title_back_rect, kWhite);
}
if (desc_style.has_background_color()) {
draw_tool_->FillRect(row_rects.desc_back_rect,
StyleColorToRGBA(desc_style.background_color()));
} else {
draw_tool_->FillRect(row_rects.desc_back_rect, kWhite);
}
}
text_renderer_->RenderText(info.title(), row_rects.title_rect,
FontSpec::FONTSET_INFOLIST_TITLE);
text_renderer_->RenderText(info.description(), row_rects.desc_rect,
FontSpec::FONTSET_INFOLIST_DESCRIPTION);
return row_rects.whole_rect.Height();
}
void InfolistWindow::Initialize() {
text_renderer_->Initialize(GetCanvasWidget()->window);
}
void InfolistWindow::ReloadFontConfig(const string &font_description) {
text_renderer_->ReloadFontConfig(font_description);
}
} // namespace gtk
} // namespace renderer
} // namespace mozc