Back to index

nux  3.0.0
Button.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright 2010 Inalogic® Inc.
00003  *
00004  * This program is free software: you can redistribute it and/or modify it
00005  * under the terms of the GNU Lesser General Public License, as
00006  * published by the  Free Software Foundation; either version 2.1 or 3.0
00007  * of the License.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranties of
00011  * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
00012  * PURPOSE.  See the applicable version of the GNU Lesser General Public
00013  * License for more details.
00014  *
00015  * You should have received a copy of both the GNU Lesser General Public
00016  * License along with this program. If not, see <http://www.gnu.org/licenses/>
00017  *
00018  * Authored by: Jay Taoko <jaytaoko@inalogic.com>
00019  *
00020  */
00021 
00022 #include "Nux.h"
00023 #include "Button.h"
00024 #include "StaticText.h"
00025 #include "HLayout.h"
00026 #include "VLayout.h"
00027 #include "TextureArea.h"
00028 
00029 namespace nux
00030 {
00031   NUX_IMPLEMENT_OBJECT_TYPE(Button);
00032 
00033   Button::Button(TextureArea *image, NUX_FILE_LINE_DECL)
00034   : AbstractButton(NUX_FILE_LINE_PARAM)
00035   {
00036     image_ = NULL;
00037     Initialize(std::string(), image);
00038   }
00039 
00040   Button::Button(const std::string& button_label, NUX_FILE_LINE_DECL)
00041   : AbstractButton(NUX_FILE_LINE_PARAM)
00042   {
00043     image_ = NULL;
00044     Initialize(button_label, NULL);
00045   }
00046 
00047   Button::Button(const std::string& button_label, TextureArea *image, NUX_FILE_LINE_DECL)
00048   : AbstractButton(NUX_FILE_LINE_PARAM)
00049   {
00050     image_ = NULL;
00051     Initialize(button_label, image);
00052   }
00053 
00054   Button::Button(NUX_FILE_LINE_DECL)
00055   : AbstractButton(NUX_FILE_LINE_PARAM)
00056   {
00057     image_ = NULL;
00058     Initialize(std::string(), NULL);
00059   }
00060 
00061   Button::~Button()
00062   {
00063     if (image_)
00064       image_->UnReference();
00065 
00066     if (static_text_)
00067       static_text_->UnReference();
00068   }
00069 
00070   void Button::Initialize(const std::string &str, TextureArea *image)
00071   {
00072     same_size_as_content_ = true;
00073     persistent_active_state_ = false;
00074     layout_type_ = HORIZONTAL;
00075     item_order_ = IMAGE_FIRST;
00076     distribution_ = CENTER_OF_LAYOUT;
00077     space_between_items_ = 0;
00078     
00079     layout_top_padding_ = 2;
00080     layout_right_padding_ = 2;
00081     layout_bottom_padding_ = 2;
00082     layout_left_padding_ = 2;
00083 
00084     int clip = 2;
00085     left_clip_ = clip;
00086     right_clip_ = clip;
00087     top_clip_ = clip;
00088     bottom_clip_ = clip;
00089 
00090 
00091     // Set Geometry
00092     SetMinimumSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT);
00093 
00094     image_minimum_size_ = Size(16, 16);
00095     image_maximum_size_ = Size(AREA_MAX_WIDTH, AREA_MAX_HEIGHT);
00096     BuildLayout(str, image);
00097   }
00098 
00099   void Button::SetImage(TextureArea *image)
00100   {
00101     if (image == NULL)
00102       return;
00103     BuildLayout(label_, image);
00104   }
00105 
00106   void Button::SetLabel(const std::string &button_label)
00107   {
00108     BuildLayout(button_label, image_);
00109   }
00110 
00111   TextureArea* Button::GetImage()
00112   {
00113     if (image_ == NULL)
00114       return NULL;
00115 
00116     TextureArea *texture_area = new TextureArea();
00117     texture_area->SetPaintLayer(image_->GetPaintLayer());
00118 
00119     return texture_area;
00120   }
00121 
00122   std::string Button::GetLabel() const
00123   {
00124     return label_;
00125   }
00126 
00127   void Button::SetImageMinimumSize(int width, int height)
00128   {
00129     image_minimum_size_ = Size(width, height);
00130     if (image_)
00131       image_->SetMinimumSize(width, height);
00132   }
00133 
00134   void Button::SetImageMaximumSize(int width, int height)
00135   {
00136     image_maximum_size_ = Size(width, height);
00137     if (image_)
00138       image_->SetMaximumSize(width, height);
00139   }
00140 
00141   void Button::SetLayoutPadding(int top, int right, int bottom, int left)
00142   {
00143     layout_top_padding_ = top >= 0 ? top : 0;
00144     layout_right_padding_ = right >= 0 ? right : 0;
00145     layout_bottom_padding_ = bottom >= 0 ? bottom : 0;
00146     layout_left_padding_ = left >= 0 ? left : 0;
00147 
00148     if (view_layout_)
00149     {
00150       static_cast<LinearLayout*>(view_layout_)->SetPadding(layout_top_padding_,
00151         layout_right_padding_,
00152         layout_bottom_padding_,
00153         layout_left_padding_);
00154     }
00155     ComputeContentSize();
00156     QueueDraw();
00157   }
00158 
00159   void Button::SetButtonClipRegion(int top_clip, int right_clip, int bottom_clip, int left_clip)
00160   {
00161     top_clip_ = top_clip >= 0 ? top_clip : 0;
00162     right_clip_ = right_clip >= 0 ? right_clip : 0;
00163     bottom_clip_ = bottom_clip >= 0 ? bottom_clip : 0;
00164     left_clip_ = left_clip >= 0 ? left_clip : 0;
00165   }
00166 
00167   void Button::BuildLayout(const std::string &str, TextureArea* image)
00168   {
00169     if (image_ != image)
00170     {
00171       if (image_)
00172       {
00173         image_->UnReference();
00174         nuxAssert(image_->GetReferenceCount() == 1);
00175         image_ = NULL;
00176       }
00177 
00178       if (image)
00179       {
00180         image_ = new TextureArea();
00181         image_->Reference();
00182         // WARNING: GetPaintLayer returns a clone and SetPaintLayer makes a copy of the clone
00183         // UnReference temp otherwise it will be lost and cause a mem leak.
00184         AbstractPaintLayer *temp = image->GetPaintLayer();
00185         image_->SetPaintLayer(temp);
00186         delete temp;
00187 
00188         SetImageMinimumSize(image->GetMinimumWidth(), image->GetMinimumHeight());
00189         SetImageMaximumSize(image->GetMaximumWidth(), image->GetMaximumHeight());
00190       }
00191     }
00192 
00193     bool create_new_text = false;
00194     if (static_text_ && (str != static_text_->GetText()))
00195     {
00196       create_new_text = true;
00197     }
00198 
00199     if ((static_text_ == NULL) && (str != ""))
00200     {
00201       create_new_text = true;
00202     }
00203 
00204     if (create_new_text)
00205     {
00206       if (static_text_)
00207       {
00208         static_text_->UnReference();
00209         nuxAssert(static_text_->GetReferenceCount() == 1);
00210         static_text_ = NULL;
00211       }
00212 
00213       if (str != "")
00214       {
00215         label_ = str;
00216         static_text_ = new StaticText(str, NUX_TRACKER_LOCATION);
00217         static_text_->Reference();
00218         static_text_->SetTextColor(label_color_);
00219       }
00220     }
00221 
00222     RemoveLayout();
00223 
00224     LinearLayout *layout = NULL;
00225     if (static_text_ && image_)
00226     {
00227       if ((layout_type_ == HORIZONTAL) && (item_order_ == IMAGE_FIRST))
00228       {
00229         layout = new HLayout(NUX_TRACKER_LOCATION);
00230         layout->AddView(image_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT);
00231         layout->AddView(static_text_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT);
00232         layout->SetHorizontalInternalMargin(space_between_items_);
00233       }
00234       else if ((layout_type_ == HORIZONTAL) && (item_order_ == LABEL_FIRST))
00235       {
00236         layout = new HLayout(NUX_TRACKER_LOCATION);
00237         layout->AddView(static_text_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT);
00238         layout->AddView(image_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT);
00239         layout->SetHorizontalInternalMargin(space_between_items_);
00240       }
00241       else if ((layout_type_ == VERTICAL) && (item_order_ == IMAGE_FIRST))
00242       {
00243         layout = new VLayout(NUX_TRACKER_LOCATION);
00244         layout->AddView(image_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT);
00245         layout->AddView(static_text_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT);
00246         layout->SetVerticalInternalMargin(space_between_items_);
00247       }
00248       else if ((layout_type_ == VERTICAL) && (item_order_ == LABEL_FIRST))
00249       {
00250         layout = new VLayout(NUX_TRACKER_LOCATION);
00251         layout->AddView(static_text_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT);
00252         layout->AddView(image_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT);
00253         layout->SetVerticalInternalMargin(space_between_items_);
00254       }
00255 
00256       // Both image_ and static_text_ have a reference count of 2.
00257       nuxAssert(image_->GetReferenceCount() == 2);
00258       nuxAssert(static_text_->GetReferenceCount() == 2);
00259     }
00260     else if (static_text_)
00261     {
00262       if (layout_type_ == HORIZONTAL)
00263       {
00264         layout = new HLayout(NUX_TRACKER_LOCATION);
00265         layout->AddView(static_text_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT);
00266       }
00267       else if (layout_type_ == VERTICAL)
00268       {
00269         layout = new VLayout(NUX_TRACKER_LOCATION);
00270         layout->AddView(static_text_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT);
00271       }
00272       nuxAssert(static_text_->GetReferenceCount() == 2);
00273     }
00274     else if (image_)
00275     {
00276       if (layout_type_ == HORIZONTAL)
00277       {
00278         layout = new HLayout(NUX_TRACKER_LOCATION);
00279         layout->AddView(image_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT);
00280       }
00281       else if (layout_type_ == VERTICAL)
00282       {
00283         layout = new VLayout(NUX_TRACKER_LOCATION);
00284         layout->AddView(image_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT);
00285       }
00286       nuxAssert(image_->GetReferenceCount() == 2);
00287     }
00288 
00289     if (static_text_)
00290     {
00291       static_text_->SetInputEventSensitivity(false);
00292       static_text_->SetTextPointSize(label_font_size_);
00293     }
00294 
00295     if (image_)
00296     {
00297       image_->SetInputEventSensitivity(false);
00298     }
00299 
00300 
00301     if (layout)
00302     {
00303       switch(distribution_)
00304       {
00305       case START_OF_LAYOUT:
00306         layout->SetContentDistribution(MAJOR_POSITION_LEFT);
00307         break;
00308 
00309       case END_OF_LAYOUT:
00310         layout->SetContentDistribution(MAJOR_POSITION_RIGHT);
00311         break;
00312 
00313       case CENTER_OF_LAYOUT:
00314         layout->SetContentDistribution(MAJOR_POSITION_CENTER);
00315         break;
00316 
00317       case SPREAD_OVER_LAYOUT:
00318         layout->SetContentDistribution(MAJOR_POSITION_SPREAD);
00319         break;
00320       }
00321     }
00322 
00323     if (layout)
00324     {
00325       layout->SetHorizontalInternalMargin(space_between_items_);
00326       layout->SetPadding(layout_top_padding_,
00327         layout_right_padding_,
00328         layout_bottom_padding_,
00329         layout_left_padding_);
00330     }
00331 
00332     if (layout)
00333     {
00334       SetLayout(layout);
00335     }
00336 
00337     ComputeContentSize();
00338 
00339     QueueDraw();
00340   }
00341 
00342   void Button::Draw(GraphicsEngine &graphics_engine, bool force_draw)
00343   {
00344     Geometry base = GetGeometry();
00345 
00346     graphics_engine.PushClippingRectangle(base);
00347     GetPainter().PaintBackground(graphics_engine, base);
00348 
00349     if (visual_state_ == VISUAL_STATE_PRESSED)
00350     {
00351       GetPainter().PaintTextureShape(graphics_engine, base, eBUTTON_FOCUS);
00352     }
00353     else if (visual_state_ == VISUAL_STATE_PRELIGHT)
00354     {
00355       GetPainter().PaintTextureShape(graphics_engine, base, eBUTTON_PRELIGHT);
00356     }
00357     else
00358     {
00359       GetPainter().PaintTextureShape(graphics_engine, base, eBUTTON_NORMAL);
00360     }
00361 
00362     if (GetCompositionLayout())
00363     {
00364       GetPainter().PushPaintLayerStack();
00365       {
00366         Geometry clip_geo = base;
00367         clip_geo.OffsetPosition(left_clip_, top_clip_);
00368         clip_geo.OffsetSize(-left_clip_ - right_clip_, -top_clip_ - bottom_clip_);
00369 
00370         graphics_engine.PushClippingRectangle(clip_geo);
00371         GetPainter().PushPaintLayerStack();
00372         GetCompositionLayout()->ProcessDraw(graphics_engine, force_draw);
00373         GetPainter().PopPaintLayerStack();
00374         graphics_engine.PopClippingRectangle();
00375       }
00376       GetPainter().PopPaintLayerStack();
00377     }
00378     graphics_engine.PopClippingRectangle();
00379   }
00380 
00381   long Button::ComputeContentSize()
00382   {
00383     return View::ComputeContentSize();
00384   }
00385 
00386   void Button::Activate()
00387   {
00388     if (persistent_active_state_ == false)
00389     {
00390       return;
00391     }
00392 
00393     if (active_ == true)
00394     {
00395       // already active
00396       return;
00397     }
00398 
00399     active_ = true;
00400     
00401     state_change.emit(this);
00402     QueueDraw();
00403   }
00404 
00405   void Button::Deactivate()
00406   {
00407     if (persistent_active_state_ == false)
00408     {
00409       return;
00410     }
00411 
00412     if (active_ == false)
00413     {
00414       // already deactivated
00415       return;
00416     }
00417 
00418     active_ = false;
00419 
00420     state_change.emit(this);
00421     QueueDraw();
00422   }
00423 
00424   void Button::RecvClick(int x, int y, unsigned long button_flags, unsigned long key_flags)
00425   {
00426     if (persistent_active_state_)
00427     {
00428       active_ = !active_;
00429     }
00430 
00431     click.emit(this);
00432     state_change.emit(this);
00433     QueueDraw();
00434   }
00435 
00436   void Button::SetDistribution(Distribution distribution)
00437   {
00438     distribution_ = distribution;
00439     BuildLayout(label_, image_);
00440   }
00441 
00442   void Button::SetItemOrder(ItemOrder item_order)
00443   {
00444     item_order_ = item_order;
00445     BuildLayout(label_, image_);
00446   }
00447 
00448   void Button::SetLayoutType(LayoutType layout_type)
00449   {
00450     layout_type_ = layout_type;
00451     BuildLayout(label_, image_);
00452   }
00453 
00454   void Button::SetSpaceBetweenItems(int space_between_items)
00455   {
00456     space_between_items_ = (space_between_items >= 0) ? space_between_items : 0;
00457     if (view_layout_)
00458     {
00459       static_cast<LinearLayout*>(view_layout_)->SetSpaceBetweenChildren(space_between_items_);
00460     }
00461 
00462     ComputeContentSize();
00463     QueueDraw();
00464 
00465   }
00466 
00467   void Button::SetLabelFontSize(int point)
00468   {
00469     AbstractButton::SetLabelFontSize(point);
00470 
00471     if (static_text_ == NULL)
00472       return;
00473 
00474     ComputeContentSize();
00475     QueueDraw();
00476   }
00477 }