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, >k_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