Home | History | Annotate | Download | only in infobars
      1 // Copyright (c) 2011 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 "chrome/browser/ui/gtk/infobars/translate_infobar_base_gtk.h"
      6 
      7 #include "base/utf_string_conversions.h"
      8 #include "chrome/browser/translate/options_menu_model.h"
      9 #include "chrome/browser/translate/translate_infobar_delegate.h"
     10 #include "chrome/browser/ui/gtk/gtk_util.h"
     11 #include "chrome/browser/ui/gtk/infobars/after_translate_infobar_gtk.h"
     12 #include "chrome/browser/ui/gtk/infobars/before_translate_infobar_gtk.h"
     13 #include "chrome/browser/ui/gtk/infobars/translate_message_infobar_gtk.h"
     14 #include "chrome/browser/ui/gtk/menu_gtk.h"
     15 #include "grit/generated_resources.h"
     16 #include "ui/base/animation/slide_animation.h"
     17 #include "ui/base/l10n/l10n_util.h"
     18 #include "ui/gfx/canvas.h"
     19 
     20 namespace {
     21 
     22 // To be able to map from language id <-> entry in the combo box, we
     23 // store the language id in the combo box data model in addition to the
     24 // displayed name.
     25 enum {
     26   LANGUAGE_COMBO_COLUMN_ID,
     27   LANGUAGE_COMBO_COLUMN_NAME,
     28   LANGUAGE_COMBO_COLUMN_COUNT
     29 };
     30 
     31 }  // namespace
     32 
     33 TranslateInfoBarBase::TranslateInfoBarBase(TranslateInfoBarDelegate* delegate)
     34     : InfoBar(delegate) {
     35   TranslateInfoBarDelegate::BackgroundAnimationType animation =
     36       delegate->background_animation_type();
     37   if (animation != TranslateInfoBarDelegate::NONE) {
     38     background_color_animation_.reset(new ui::SlideAnimation(this));
     39     background_color_animation_->SetTweenType(ui::Tween::LINEAR);
     40     background_color_animation_->SetSlideDuration(500);
     41     if (animation == TranslateInfoBarDelegate::NORMAL_TO_ERROR) {
     42       background_color_animation_->Show();
     43     } else {
     44       DCHECK_EQ(TranslateInfoBarDelegate::ERROR_TO_NORMAL, animation);
     45       // Hide() runs the animation in reverse.
     46       background_color_animation_->Reset(1.0);
     47       background_color_animation_->Hide();
     48     }
     49   } else {
     50     background_error_percent_ = delegate->IsError() ? 1 : 0;
     51   }
     52 }
     53 
     54 TranslateInfoBarBase::~TranslateInfoBarBase() {
     55 }
     56 
     57 void TranslateInfoBarBase::Init() {
     58   if (!ShowOptionsMenuButton())
     59     return;
     60 
     61   // The options button sits outside the translate_box so that it can be end
     62   // packed in hbox_.
     63   GtkWidget* options_menu_button = BuildOptionsMenuButton();
     64   g_signal_connect(options_menu_button, "clicked",
     65                    G_CALLBACK(&OnOptionsClickedThunk), this);
     66   gtk_widget_show_all(options_menu_button);
     67   gtk_util::CenterWidgetInHBox(hbox_, options_menu_button, true, 0);
     68 }
     69 
     70 void TranslateInfoBarBase::GetTopColor(InfoBarDelegate::Type type,
     71                                        double* r, double* g, double *b) {
     72   if (background_error_percent_ <= 0) {
     73     InfoBar::GetTopColor(InfoBarDelegate::PAGE_ACTION_TYPE, r, g, b);
     74   } else if (background_error_percent_ >= 1) {
     75     InfoBar::GetTopColor(InfoBarDelegate::WARNING_TYPE, r, g, b);
     76   } else {
     77     double normal_r, normal_g, normal_b;
     78     InfoBar::GetTopColor(InfoBarDelegate::PAGE_ACTION_TYPE,
     79                          &normal_r, &normal_g, &normal_b);
     80 
     81     double error_r, error_g, error_b;
     82     InfoBar::GetTopColor(InfoBarDelegate::WARNING_TYPE,
     83                          &error_r, &error_g, &error_b);
     84 
     85     double offset_r = error_r - normal_r;
     86     double offset_g = error_g - normal_g;
     87     double offset_b = error_b - normal_b;
     88 
     89     *r = normal_r + (background_error_percent_ * offset_r);
     90     *g = normal_g + (background_error_percent_ * offset_g);
     91     *b = normal_b + (background_error_percent_ * offset_b);
     92   }
     93 }
     94 
     95 void TranslateInfoBarBase::GetBottomColor(InfoBarDelegate::Type type,
     96                                           double* r, double* g, double *b) {
     97   if (background_error_percent_ <= 0) {
     98     InfoBar::GetBottomColor(InfoBarDelegate::PAGE_ACTION_TYPE, r, g, b);
     99   } else if (background_error_percent_ >= 1) {
    100     InfoBar::GetBottomColor(InfoBarDelegate::WARNING_TYPE, r, g, b);
    101   } else {
    102     double normal_r, normal_g, normal_b;
    103     InfoBar::GetBottomColor(InfoBarDelegate::PAGE_ACTION_TYPE,
    104                             &normal_r, &normal_g, &normal_b);
    105 
    106     double error_r, error_g, error_b;
    107     InfoBar::GetBottomColor(InfoBarDelegate::WARNING_TYPE,
    108                             &error_r, &error_g, &error_b);
    109 
    110     double offset_r = error_r - normal_r;
    111     double offset_g = error_g - normal_g;
    112     double offset_b = error_b - normal_b;
    113 
    114     *r = normal_r + (background_error_percent_ * offset_r);
    115     *g = normal_g + (background_error_percent_ * offset_g);
    116     *b = normal_b + (background_error_percent_ * offset_b);
    117   }
    118 }
    119 
    120 void TranslateInfoBarBase::AnimationProgressed(const ui::Animation* animation) {
    121   DCHECK(animation == background_color_animation_.get());
    122   background_error_percent_ = animation->GetCurrentValue();
    123   // Queue the info bar widget for redisplay so it repaints its background.
    124   gtk_widget_queue_draw(widget());
    125 }
    126 
    127 bool TranslateInfoBarBase::ShowOptionsMenuButton() const {
    128   return false;
    129 }
    130 
    131 GtkWidget* TranslateInfoBarBase::CreateLabel(const std::string& text) {
    132   GtkWidget* label = gtk_label_new(text.c_str());
    133   gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &gtk_util::kGdkBlack);
    134   return label;
    135 }
    136 
    137 GtkWidget* TranslateInfoBarBase::CreateLanguageCombobox(
    138     size_t selected_language,
    139     size_t exclude_language) {
    140   GtkListStore* model = gtk_list_store_new(LANGUAGE_COMBO_COLUMN_COUNT,
    141                                            G_TYPE_INT, G_TYPE_STRING);
    142   bool set_selection = false;
    143   GtkTreeIter selected_iter;
    144   TranslateInfoBarDelegate* delegate = GetDelegate();
    145   for (size_t i = 0; i < delegate->GetLanguageCount(); ++i) {
    146     if (i == exclude_language)
    147       continue;
    148     GtkTreeIter tree_iter;
    149     const string16& name = delegate->GetLanguageDisplayableNameAt(i);
    150 
    151     gtk_list_store_append(model, &tree_iter);
    152     gtk_list_store_set(model, &tree_iter,
    153                        LANGUAGE_COMBO_COLUMN_ID, i,
    154                        LANGUAGE_COMBO_COLUMN_NAME, UTF16ToUTF8(name).c_str(),
    155                        -1);
    156     if (i == selected_language) {
    157       selected_iter = tree_iter;
    158       set_selection = true;
    159     }
    160   }
    161 
    162   GtkWidget* combobox = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model));
    163   if (set_selection)
    164     gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combobox), &selected_iter);
    165   g_object_unref(model);
    166   GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
    167   gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), renderer, TRUE);
    168   gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combobox), renderer,
    169                                  "text", LANGUAGE_COMBO_COLUMN_NAME,
    170                                  NULL);
    171   return combobox;
    172 }
    173 
    174 // static
    175 size_t TranslateInfoBarBase::GetLanguageComboboxActiveId(GtkComboBox* combo) {
    176   GtkTreeIter iter;
    177   if (!gtk_combo_box_get_active_iter(combo, &iter))
    178     return 0;
    179 
    180   gint id = 0;
    181   gtk_tree_model_get(gtk_combo_box_get_model(combo), &iter,
    182                      LANGUAGE_COMBO_COLUMN_ID, &id,
    183                      -1);
    184   return static_cast<size_t>(id);
    185 }
    186 
    187 TranslateInfoBarDelegate* TranslateInfoBarBase::GetDelegate() const {
    188   return static_cast<TranslateInfoBarDelegate*>(delegate());
    189 }
    190 
    191 // static
    192 GtkWidget* TranslateInfoBarBase::BuildOptionsMenuButton() {
    193   GtkWidget* button = gtk_button_new();
    194   GtkWidget* former_child = gtk_bin_get_child(GTK_BIN(button));
    195   if (former_child)
    196     gtk_container_remove(GTK_CONTAINER(button), former_child);
    197 
    198   GtkWidget* hbox = gtk_hbox_new(FALSE, 0);
    199 
    200   GtkWidget* label = gtk_label_new(
    201       l10n_util::GetStringUTF8(IDS_TRANSLATE_INFOBAR_OPTIONS).c_str());
    202   gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
    203 
    204   GtkWidget* arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE);
    205   gtk_box_pack_start(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
    206 
    207   gtk_container_add(GTK_CONTAINER(button), hbox);
    208 
    209   return button;
    210 }
    211 
    212 void TranslateInfoBarBase::OnOptionsClicked(GtkWidget* sender) {
    213   if (!options_menu_model_.get()) {
    214     options_menu_model_.reset(new OptionsMenuModel(GetDelegate()));
    215     options_menu_menu_.reset(new MenuGtk(NULL, options_menu_model_.get()));
    216   }
    217   options_menu_menu_->PopupForWidget(sender, 1, gtk_get_current_event_time());
    218 }
    219 
    220 // TranslateInfoBarDelegate specific method:
    221 InfoBar* TranslateInfoBarDelegate::CreateInfoBar() {
    222   TranslateInfoBarBase* infobar = NULL;
    223   switch (type_) {
    224     case BEFORE_TRANSLATE:
    225       infobar = new BeforeTranslateInfoBar(this);
    226       break;
    227     case AFTER_TRANSLATE:
    228       infobar = new AfterTranslateInfoBar(this);
    229       break;
    230     case TRANSLATING:
    231     case TRANSLATION_ERROR:
    232       infobar = new TranslateMessageInfoBar(this);
    233       break;
    234     default:
    235       NOTREACHED();
    236   }
    237   infobar->Init();
    238   return infobar;
    239 }
    240