| 1 | ///////////////////////////////////////////////////////////////////////////// |
| 2 | // Name: foldpanelbar.cpp |
| 3 | // Purpose: |
| 4 | // Author: Jorgen Bodde |
| 5 | // Modified by: ABX - 19/12/2004 : possibility of horizontal orientation |
| 6 | // : wxWidgets coding standards |
| 7 | // Created: 22/06/2004 |
| 8 | // RCS-ID: $Id$ |
| 9 | // Copyright: (c) Jorgen Bodde |
| 10 | // Licence: wxWindows licence |
| 11 | ///////////////////////////////////////////////////////////////////////////// |
| 12 | |
| 13 | // For compilers that support precompilation, includes "wx/wx.h". |
| 14 | #include "wx/wxprec.h" |
| 15 | |
| 16 | #ifdef __BORLANDC__ |
| 17 | #pragma hdrstop |
| 18 | #endif |
| 19 | |
| 20 | #ifndef WX_PRECOMP |
| 21 | #include "wx/wx.h" |
| 22 | #endif |
| 23 | |
| 24 | #include "wx/foldbar/foldpanelbar.h" |
| 25 | #include "icon_collapsed.xpm" |
| 26 | #include "icon_expanded.xpm" |
| 27 | #include "icon_theresmore.xpm" |
| 28 | |
| 29 | //---------------------------------------------------------------------------- |
| 30 | // wxFoldPanelBar |
| 31 | //---------------------------------------------------------------------------- |
| 32 | |
| 33 | IMPLEMENT_DYNAMIC_CLASS( wxFoldPanelBar, wxPanel ) |
| 34 | |
| 35 | BEGIN_EVENT_TABLE(wxFoldPanelBar,wxPanel) |
| 36 | EVT_SIZE(wxFoldPanelBar::OnSizePanel) |
| 37 | //EVT_PAINT(wxFoldPanelBar::OnPaint) |
| 38 | EVT_CAPTIONBAR(wxID_ANY, wxFoldPanelBar::OnPressCaption) |
| 39 | END_EVENT_TABLE() |
| 40 | |
| 41 | wxFoldPanelBar::wxFoldPanelBar() |
| 42 | : wxPanel() |
| 43 | , m_foldPanel(NULL) |
| 44 | , m_bottomPanel(NULL) |
| 45 | , m_controlCreated(false) |
| 46 | { |
| 47 | |
| 48 | } |
| 49 | |
| 50 | wxFoldPanelBar::wxFoldPanelBar( wxWindow *parent, wxWindowID id, const wxPoint &position, |
| 51 | const wxSize& size, long style, long extraStyle) |
| 52 | : wxPanel() |
| 53 | , m_foldPanel(NULL) |
| 54 | , m_bottomPanel(NULL) |
| 55 | , m_controlCreated(false) |
| 56 | { |
| 57 | Create( parent, id, position, size, style, extraStyle); |
| 58 | } |
| 59 | |
| 60 | void wxFoldPanelBar::Create( wxWindow *parent, wxWindowID id, const wxPoint &position, |
| 61 | const wxSize& size, long style, long extraStyle ) |
| 62 | { |
| 63 | |
| 64 | m_extraStyle = extraStyle; |
| 65 | |
| 66 | // make sure there is any orientation |
| 67 | if ( ( style & wxFPB_HORIZONTAL ) != wxFPB_HORIZONTAL ) |
| 68 | style |= wxFPB_VERTICAL; |
| 69 | |
| 70 | // create the panel (duh!). This causes a size event, which we are going |
| 71 | // to skip when we are not initialised |
| 72 | |
| 73 | wxPanel::Create(parent, id, position, size, style); |
| 74 | |
| 75 | // the fold panel area |
| 76 | |
| 77 | m_foldPanel = new wxPanel(this, wxID_ANY, position, size, wxNO_BORDER|wxTAB_TRAVERSAL); |
| 78 | |
| 79 | // the extra area for some icons / context menu etc |
| 80 | |
| 81 | #if 0 |
| 82 | m_bottomPanel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(wxDefaultCoord,22), wxNO_BORDER|wxTAB_TRAVERSAL); |
| 83 | m_bottomPanel->SetBackgroundColour(*wxWHITE); |
| 84 | #endif |
| 85 | |
| 86 | // create the fold icons to be used in the captions |
| 87 | |
| 88 | m_images = new wxImageList(16, 16); |
| 89 | |
| 90 | wxBitmap *bmp = new wxBitmap(icon_expanded); |
| 91 | m_images->Add(*bmp); |
| 92 | delete bmp; |
| 93 | |
| 94 | bmp = new wxBitmap(icon_collapsed); |
| 95 | m_images->Add(*bmp); |
| 96 | delete bmp; |
| 97 | |
| 98 | m_moreBmp = new wxBitmap(icon_theresmore); |
| 99 | |
| 100 | // do this as last, to check if create is already called |
| 101 | |
| 102 | m_controlCreated = true; |
| 103 | } |
| 104 | |
| 105 | wxFoldPanelBar::~wxFoldPanelBar() |
| 106 | { |
| 107 | delete m_images; |
| 108 | delete m_moreBmp; |
| 109 | } |
| 110 | |
| 111 | wxFoldPanel wxFoldPanelBar::AddFoldPanel(const wxString &caption, bool collapsedInitially, const wxCaptionBarStyle &style) |
| 112 | { |
| 113 | wxASSERT(m_controlCreated); |
| 114 | |
| 115 | // create a fold panel item, which is first only the caption. |
| 116 | // the user can now add a panel area which will be folded in |
| 117 | // when pressed. |
| 118 | |
| 119 | wxFoldPanelItem *item = new wxFoldPanelItem(m_foldPanel, caption, m_images, collapsedInitially, style); |
| 120 | |
| 121 | // look at the last added one and reposition this one |
| 122 | int pos = 0; |
| 123 | if(m_panels.GetCount() > 0) |
| 124 | pos = m_panels.Last()->GetItemPos() + m_panels.Last()->GetPanelLength(); |
| 125 | |
| 126 | item->Reposition(pos); |
| 127 | m_panels.Add(item); |
| 128 | |
| 129 | //return wxFoldPanel(item); |
| 130 | return wxFoldPanel(item); |
| 131 | } |
| 132 | |
| 133 | int wxFoldPanelBar::AddFoldPanelWindow(const wxFoldPanel &panel, wxWindow *window, int flags, int ySpacing, int leftSpacing, |
| 134 | int rightSpacing) |
| 135 | { |
| 136 | wxCHECK(panel.IsOk(), -1); |
| 137 | panel.GetItem()->AddWindow(window, flags, ySpacing, leftSpacing, rightSpacing); |
| 138 | |
| 139 | // TODO: Take old and new height, and if difference, reposition all the lower panels |
| 140 | // this is because the user can add new wxWindow controls somewhere in between |
| 141 | // when other panels are already present. |
| 142 | |
| 143 | return 0; |
| 144 | } |
| 145 | |
| 146 | int wxFoldPanelBar::AddFoldPanelSeperator(const wxFoldPanel &panel, const wxColour &color, int ySpacing, int leftSpacing, |
| 147 | int rightSpacing) |
| 148 | { |
| 149 | wxCHECK(panel.IsOk(), -1); |
| 150 | panel.GetItem()->AddSeparator(color, ySpacing, leftSpacing, rightSpacing); |
| 151 | |
| 152 | return 0; |
| 153 | } |
| 154 | |
| 155 | void wxFoldPanelBar::OnSizePanel(wxSizeEvent &event) |
| 156 | { |
| 157 | // skip all stuff when we are not initialised yet |
| 158 | |
| 159 | if(!m_controlCreated) |
| 160 | { |
| 161 | event.Skip(); |
| 162 | return; |
| 163 | } |
| 164 | |
| 165 | // now size the fold panel area and the |
| 166 | // lower bar in such a way that the bar is always |
| 167 | // visible |
| 168 | |
| 169 | wxRect foldrect = GetRect(); |
| 170 | |
| 171 | // fold panel itself. If too little space, |
| 172 | // don't show it |
| 173 | |
| 174 | #if 0 |
| 175 | if(foldrect.GetHeight() < 23) |
| 176 | foldrect.SetHeight(0); |
| 177 | else |
| 178 | foldrect.SetHeight(foldrect.GetHeight() - 22); |
| 179 | #endif |
| 180 | |
| 181 | foldrect.SetX(0); |
| 182 | foldrect.SetY(0); |
| 183 | m_foldPanel->SetSize(foldrect); |
| 184 | |
| 185 | if(m_extraStyle & wxFPB_COLLAPSE_TO_BOTTOM) |
| 186 | { |
| 187 | wxRect rect = RepositionCollapsedToBottom(); |
| 188 | bool vertical = IsVertical(); |
| 189 | if((vertical && rect.GetHeight() > 0) || (!vertical && rect.GetWidth() > 0)) |
| 190 | RefreshRect(rect); |
| 191 | } |
| 192 | |
| 193 | // TODO: A smart way to check wether the old - new width of the |
| 194 | // panel changed, if so no need to resize the fold panel items |
| 195 | |
| 196 | RedisplayFoldPanelItems(); |
| 197 | |
| 198 | // tool panel for icons and other stuff |
| 199 | |
| 200 | #if 0 |
| 201 | wxRect bottomrect = GetRect(); |
| 202 | if(bottomrect.GetHeight() < 22) |
| 203 | bottomrect.SetY(0); |
| 204 | else |
| 205 | bottomrect.SetY(bottomrect.GetHeight() - 22); |
| 206 | |
| 207 | bottomrect.SetHeight(22); |
| 208 | bottomrect.SetX(0); |
| 209 | m_bottomPanel->SetSize(bottomrect); |
| 210 | |
| 211 | // TODO: redraw the bitmap properly |
| 212 | // use the captionbar algorithm for that |
| 213 | |
| 214 | m_bottomPanel->Refresh(); |
| 215 | #endif |
| 216 | } |
| 217 | |
| 218 | void wxFoldPanelBar::OnPaint(wxPaintEvent &event) |
| 219 | { |
| 220 | if(!m_controlCreated) |
| 221 | return; |
| 222 | #if 0 |
| 223 | // paint the bottom panel only, where the |
| 224 | // arrow is shown when there is more to show the user |
| 225 | // just as informative icon |
| 226 | |
| 227 | wxPaintDC dc(m_bottomPanel); |
| 228 | |
| 229 | wxSize size = m_bottomPanel->GetSize(); |
| 230 | int offset = (size.GetHeight() - m_moreBmp->GetHeight()) / 2; |
| 231 | |
| 232 | dc.DrawBitmap(*m_moreBmp, size.GetWidth() - m_moreBmp->GetWidth() - 2, offset, true); |
| 233 | #endif |
| 234 | |
| 235 | event.Skip(); |
| 236 | } |
| 237 | |
| 238 | void wxFoldPanelBar::OnPressCaption(wxCaptionBarEvent &event) |
| 239 | { |
| 240 | // act upon the folding or expanding status of the bar |
| 241 | // to expand or collapse the panel(s) |
| 242 | |
| 243 | if(event.GetFoldStatus()) |
| 244 | Collapse(wxFoldPanel((wxFoldPanelItem *)event.GetTag())); |
| 245 | else |
| 246 | Expand(wxFoldPanel((wxFoldPanelItem *)event.GetTag())); |
| 247 | } |
| 248 | |
| 249 | void wxFoldPanelBar::RefreshPanelsFrom(wxFoldPanelItem *item) |
| 250 | { |
| 251 | wxASSERT(item); |
| 252 | |
| 253 | int i = m_panels.Index(item); |
| 254 | if(i != wxNOT_FOUND) |
| 255 | RefreshPanelsFrom(i); |
| 256 | } |
| 257 | |
| 258 | void wxFoldPanelBar::RefreshPanelsFrom(size_t i) |
| 259 | { |
| 260 | Freeze(); |
| 261 | |
| 262 | // if collapse to bottom is on, the panels that are not expanded |
| 263 | // should be drawn at the bottom. All panels that are expanded |
| 264 | // are drawn on top. The last expanded panel gets all the extra space |
| 265 | |
| 266 | if(m_extraStyle & wxFPB_COLLAPSE_TO_BOTTOM) |
| 267 | { |
| 268 | int offset = 0; |
| 269 | |
| 270 | for(size_t j = 0; j < m_panels.GetCount(); j++) |
| 271 | { |
| 272 | if(m_panels.Item(j)->IsExpanded()) |
| 273 | offset += m_panels.Item(j)->Reposition(offset); |
| 274 | } |
| 275 | |
| 276 | // put all non collapsed panels at the bottom where there is space, else |
| 277 | // put them right behind the expanded ones |
| 278 | |
| 279 | RepositionCollapsedToBottom(); |
| 280 | } |
| 281 | else |
| 282 | { |
| 283 | int pos = m_panels.Item(i)->GetItemPos() + m_panels.Item(i)->GetPanelLength(); |
| 284 | for(i++; i < m_panels.GetCount(); i++) |
| 285 | pos += m_panels.Item(i)->Reposition(pos); |
| 286 | } |
| 287 | Thaw(); |
| 288 | } |
| 289 | |
| 290 | void wxFoldPanelBar::RedisplayFoldPanelItems() |
| 291 | { |
| 292 | // resize them all. No need to reposition |
| 293 | |
| 294 | wxFoldPanelItem *item; |
| 295 | for(size_t i = 0; i < m_panels.GetCount(); i++) |
| 296 | { |
| 297 | item = m_panels.Item(i); |
| 298 | wxASSERT(item); |
| 299 | |
| 300 | item->ResizePanel(); |
| 301 | } |
| 302 | } |
| 303 | |
| 304 | wxRect wxFoldPanelBar::RepositionCollapsedToBottom() |
| 305 | { |
| 306 | wxRect value(0,0,0,0); |
| 307 | bool vertical = IsVertical(); |
| 308 | |
| 309 | // determine wether the number of panels left |
| 310 | // times the size of their captions is enough |
| 311 | // to be placed in the left over space |
| 312 | |
| 313 | int expanded = 0, collapsed = 0, offset; |
| 314 | GetPanelsLength(collapsed, expanded); |
| 315 | |
| 316 | // if no room stick them behind the normal ones, else |
| 317 | // at the bottom |
| 318 | |
| 319 | if(((vertical ? GetSize().GetHeight() : GetSize().GetWidth()) - expanded - collapsed) < 0) |
| 320 | offset = expanded; |
| 321 | else |
| 322 | { |
| 323 | // value is the region which is left unpainted |
| 324 | // I will send it back as 'slack' so it does not need to |
| 325 | // be recalulated. |
| 326 | |
| 327 | value.SetHeight(GetSize().GetHeight()); |
| 328 | value.SetWidth(GetSize().GetWidth()); |
| 329 | |
| 330 | if(vertical) |
| 331 | { |
| 332 | value.SetY(expanded); |
| 333 | value.SetHeight(value.GetHeight() - expanded); |
| 334 | } |
| 335 | else |
| 336 | { |
| 337 | value.SetX(expanded); |
| 338 | value.SetWidth(value.GetWidth() - expanded); |
| 339 | } |
| 340 | |
| 341 | offset = (vertical ? GetSize().GetHeight() : GetSize().GetWidth()) - collapsed; |
| 342 | } |
| 343 | |
| 344 | // go reposition |
| 345 | |
| 346 | for(size_t i = 0; i < m_panels.GetCount(); i++) |
| 347 | { |
| 348 | if(!m_panels.Item(i)->IsExpanded()) |
| 349 | offset += m_panels.Item(i)->Reposition(offset); |
| 350 | } |
| 351 | |
| 352 | return value; |
| 353 | } |
| 354 | |
| 355 | int wxFoldPanelBar::GetPanelsLength(int &collapsed, int &expanded) |
| 356 | { |
| 357 | int value = 0; |
| 358 | |
| 359 | // assumed here that all the panels that are expanded |
| 360 | // are positioned after each other from 0,0 to end. |
| 361 | |
| 362 | for(size_t j = 0; j < m_panels.GetCount(); j++) |
| 363 | { |
| 364 | int offset = m_panels.Item(j)->GetPanelLength(); |
| 365 | value += offset; |
| 366 | if(m_panels.Item(j)->IsExpanded()) |
| 367 | expanded += offset; |
| 368 | else |
| 369 | collapsed += offset; |
| 370 | } |
| 371 | |
| 372 | return value; |
| 373 | } |