void Tabs::drawTab(Graphics* g, const gfx::Rect& box, Tab* tab, int y_delta, bool selected) { // Is the tab outside the bounds of the widget? if (box.x >= getBounds().x2() || box.x2() <= getBounds().x) return; SkinTheme* theme = static_cast<SkinTheme*>(this->getTheme()); gfx::Color text_color; gfx::Color face_color; // Selected if (selected) { text_color = theme->getColor(ThemeColor::TabSelectedText); face_color = theme->getColor(ThemeColor::TabSelectedFace); } // Non-selected else { text_color = theme->getColor(ThemeColor::TabNormalText); face_color = theme->getColor(ThemeColor::TabNormalFace); } if (box.w > 2) { theme->draw_bounds_nw(g, gfx::Rect(box.x, box.y+y_delta, box.w, box.h), (selected) ? PART_TAB_SELECTED_NW: PART_TAB_NORMAL_NW, face_color); g->drawString(tab->text, text_color, gfx::ColorNone, gfx::Point( box.x + 4*jguiscale(), box.y + box.h/2 - getFont()->height()/2+1 + y_delta)); } if (selected) { theme->draw_bounds_nw(g, gfx::Rect(box.x, box.y2(), box.w, getBounds().y2()-box.y2()), PART_TAB_BOTTOM_SELECTED_NW, theme->getColor(ThemeColor::TabSelectedFace)); } else { theme->draw_part_as_hline(g, gfx::Rect(box.x, box.y2(), box.w, getBounds().y2()-box.y2()), PART_TAB_BOTTOM_NORMAL); } #ifdef CLOSE_BUTTON_IN_EACH_TAB she::Surface* close_icon = theme->get_part(PART_WINDOW_CLOSE_BUTTON_NORMAL); g->drawRgbaSurface(close_icon, box.x2() - 4*jguiscale() - close_icon->width(), box.y + box.h/2 - close_icon->height()/2+1 * jguiscale()); #endif }
void Tabs::drawTab(BITMAP* bmp, JRect box, Tab* tab, int y_delta, bool selected) { // Is the tab outside the bounds of the widget? if (box->x1 >= this->rc->x2 || box->x2 <= this->rc->x1) return; SkinTheme* theme = static_cast<SkinTheme*>(this->getTheme()); int text_color; int face_color; // Selected if (selected) { text_color = theme->get_tab_selected_text_color(); face_color = theme->get_tab_selected_face_color(); } // Non-selected else { text_color = theme->get_tab_normal_text_color(); face_color = theme->get_tab_normal_face_color(); } if (jrect_w(box) > 2) { theme->draw_bounds_nw(bmp, box->x1, box->y1+y_delta, box->x2-1, box->y2-1, (selected) ? PART_TAB_SELECTED_NW: PART_TAB_NORMAL_NW, face_color); jdraw_text(bmp, this->getFont(), tab->text.c_str(), box->x1+4*jguiscale(), (box->y1+box->y2)/2-text_height(this->getFont())/2+1 + y_delta, text_color, face_color, false, jguiscale()); } if (selected) { theme->draw_bounds_nw(bmp, box->x1, box->y2, box->x2-1, this->rc->y2-1, PART_TAB_BOTTOM_SELECTED_NW, theme->get_tab_selected_face_color()); } else { theme->draw_part_as_hline(bmp, box->x1, box->y2, box->x2-1, this->rc->y2-1, PART_TAB_BOTTOM_NORMAL); } #ifdef CLOSE_BUTTON_IN_EACH_TAB BITMAP* close_icon = theme->get_part(PART_WINDOW_CLOSE_BUTTON_NORMAL); set_alpha_blender(); draw_trans_sprite(doublebuffer, close_icon, box->x2-4*jguiscale()-close_icon->w, (box->y1+box->y2)/2-close_icon->h/2+1*jguiscale()); #endif }
bool Tabs::onProcessMessage(Message* msg) { SkinTheme* theme = static_cast<SkinTheme*>(this->getTheme()); switch (msg->type) { case JM_REQSIZE: msg->reqsize.w = 0; // msg->reqsize.h = 4 + jwidget_get_text_height(widget) + 5; msg->reqsize.h = theme->get_part(PART_TAB_FILLER)->h + theme->get_part(PART_TAB_BOTTOM_NORMAL)->h; return true; case JM_SETPOS: jrect_copy(this->rc, &msg->setpos.rect); setScrollX(m_scrollX); return true; case JM_DRAW: { BITMAP *doublebuffer = create_bitmap(jrect_w(&msg->draw.rect), jrect_h(&msg->draw.rect)); JRect rect = jwidget_get_rect(this); jrect_displace(rect, -msg->draw.rect.x1, -msg->draw.rect.y1); JRect box = jrect_new(rect->x1-m_scrollX, rect->y1, rect->x1-m_scrollX+2*jguiscale(), rect->y1+theme->get_part(PART_TAB_FILLER)->h); clear_to_color(doublebuffer, theme->get_window_face_color()); theme->draw_part_as_hline(doublebuffer, box->x1, box->y1, box->x2-1, box->y2-1, PART_TAB_FILLER); theme->draw_part_as_hline(doublebuffer, box->x1, box->y2, box->x2-1, rect->y2-1, PART_TAB_BOTTOM_NORMAL); box->x1 = box->x2; // For each tab... TabsListIterator it, end = m_list_of_tabs.end(); for (it = m_list_of_tabs.begin(); it != end; ++it) { Tab* tab = *it; box->x2 = box->x1 + tab->width; int x_delta = 0; int y_delta = 0; // Y-delta for animating tabs (intros and outros) if (m_ani == ANI_ADDING_TAB && m_selected == tab) { y_delta = (box->y2 - box->y1) * (ANI_ADDING_TAB_TICKS - m_ani_t) / ANI_ADDING_TAB_TICKS; } else if (m_ani == ANI_REMOVING_TAB && m_nextTabOfTheRemovedOne == tab) { x_delta += m_removedTab->width - m_removedTab->width*(1.0-std::exp(-10.0 * m_ani_t / (double)ANI_REMOVING_TAB_TICKS)); x_delta = MID(0, x_delta, m_removedTab->width); // Draw deleted tab if (m_removedTab) { JRect box2 = jrect_new(box->x1, box->y1, box->x1+x_delta, box->y2); drawTab(doublebuffer, box2, m_removedTab, 0, false); jrect_free(box2); } } box->x1 += x_delta; box->x2 += x_delta; drawTab(doublebuffer, box, tab, y_delta, (tab == m_selected)); box->x1 = box->x2; } if (m_ani == ANI_REMOVING_TAB && m_nextTabOfTheRemovedOne == NULL) { // Draw deleted tab if (m_removedTab) { int x_delta = m_removedTab->width - m_removedTab->width*(1.0-std::exp(-10.0 * m_ani_t / (double)ANI_REMOVING_TAB_TICKS)); x_delta = MID(0, x_delta, m_removedTab->width); JRect box2 = jrect_new(box->x1, box->y1, box->x1+x_delta, box->y2); drawTab(doublebuffer, box2, m_removedTab, 0, false); jrect_free(box2); box->x1 += x_delta; box->x2 = box->x1; } } /* fill the gap to the right-side */ if (box->x1 < rect->x2) { theme->draw_part_as_hline(doublebuffer, box->x1, box->y1, rect->x2-1, box->y2-1, PART_TAB_FILLER); theme->draw_part_as_hline(doublebuffer, box->x1, box->y2, rect->x2-1, rect->y2-1, PART_TAB_BOTTOM_NORMAL); } jrect_free(rect); jrect_free(box); blit(doublebuffer, ji_screen, 0, 0, msg->draw.rect.x1, msg->draw.rect.y1, doublebuffer->w, doublebuffer->h); destroy_bitmap(doublebuffer); return true; } case JM_MOUSEENTER: case JM_MOTION: calculateHot(); return true; case JM_MOUSELEAVE: if (m_hot != NULL) { m_hot = NULL; invalidate(); } return true; case JM_BUTTONPRESSED: if (m_hot != NULL) { if (m_selected != m_hot) { m_selected = m_hot; invalidate(); } if (m_selected && m_delegate) m_delegate->clickTab(this, m_selected->data, msg->mouse.flags); } return true; case JM_WHEEL: { int dx = (jmouse_z(1) - jmouse_z(0)) * jrect_w(this->rc)/6; // setScrollX(m_scrollX+dx); m_begScrollX = m_scrollX; if (m_ani != ANI_SMOOTH_SCROLL) m_endScrollX = m_scrollX + dx; else m_endScrollX += dx; // Limit endScrollX position (to improve animation ending to the correct position) { int max_x = getMaxScrollX(); m_endScrollX = MID(0, m_endScrollX, max_x); } startAni(ANI_SMOOTH_SCROLL); return true; } case JM_TIMER: { switch (m_ani) { case ANI_NONE: // Do nothing break; case ANI_SCROLL: { int dir = (getManager()->getCapture() == m_button_left ? -1: 1); setScrollX(m_scrollX + dir*8*msg->timer.count); break; } case ANI_SMOOTH_SCROLL: { if (m_ani_t == ANI_SMOOTH_SCROLL_TICKS) { stopAni(); setScrollX(m_endScrollX); } else { // Lineal //setScrollX(m_begScrollX + m_endScrollX - m_begScrollX) * m_ani_t / 10); // Exponential setScrollX(m_begScrollX + (m_endScrollX - m_begScrollX) * (1.0-std::exp(-10.0 * m_ani_t / (double)ANI_SMOOTH_SCROLL_TICKS))); } break; } case ANI_ADDING_TAB: { if (m_ani_t == ANI_ADDING_TAB_TICKS) stopAni(); invalidate(); break; } case ANI_REMOVING_TAB: { if (m_ani_t == ANI_REMOVING_TAB_TICKS) stopAni(); invalidate(); break; } } ++m_ani_t; break; } case JM_SIGNAL: if (msg->signal.num == JI_SIGNAL_INIT_THEME) { m_button_left->setBgColor(theme->get_tab_selected_face_color()); m_button_right->setBgColor(theme->get_tab_selected_face_color()); } else if (msg->signal.num == JI_SIGNAL_SET_FONT) { TabsListIterator it, end = m_list_of_tabs.end(); for (it = m_list_of_tabs.begin(); it != end; ++it) { Tab* tab = *it; tab->width = calcTabWidth(tab); } } else if (msg->signal.num == JI_SIGNAL_INIT_THEME) { /* setup the background color */ jwidget_set_bg_color(this, ji_color_face()); } break; } return Widget::onProcessMessage(msg); }
void Tabs::onPaint(PaintEvent& ev) { SkinTheme* theme = static_cast<SkinTheme*>(this->getTheme()); Graphics* g = ev.getGraphics(); gfx::Rect rect = getClientBounds(); gfx::Rect box(rect.x-m_scrollX, rect.y, 2*jguiscale(), m_list_of_tabs.empty() ? 0: theme->get_part(PART_TAB_FILLER)->height()); g->fillRect(theme->getColorById(kWindowFaceColorId), g->getClipBounds()); theme->draw_part_as_hline(g, box, PART_TAB_FILLER); theme->draw_part_as_hline(g, gfx::Rect(box.x, box.y2(), box.w, rect.y2()-box.y2()), PART_TAB_BOTTOM_NORMAL); box.x = box.x2(); // For each tab... TabsListIterator it, end = m_list_of_tabs.end(); for (it = m_list_of_tabs.begin(); it != end; ++it) { Tab* tab = *it; box.w = tab->width; int x_delta = 0; int y_delta = 0; // Y-delta for animating tabs (intros and outros) if (m_ani == ANI_ADDING_TAB && m_selected == tab) { y_delta = box.h * (ANI_ADDING_TAB_TICKS - m_ani_t) / ANI_ADDING_TAB_TICKS; } else if (m_ani == ANI_REMOVING_TAB && m_nextTabOfTheRemovedOne == tab) { x_delta += m_removedTab->width - m_removedTab->width*(1.0-std::exp(-10.0 * m_ani_t / (double)ANI_REMOVING_TAB_TICKS)); x_delta = MID(0, x_delta, m_removedTab->width); // Draw deleted tab if (m_removedTab) { gfx::Rect box2(box.x, box.y, x_delta, box.h); drawTab(g, box2, m_removedTab, 0, false); } } box.x += x_delta; drawTab(g, box, tab, y_delta, (tab == m_selected)); box.x = box.x2(); } if (m_ani == ANI_REMOVING_TAB && m_nextTabOfTheRemovedOne == NULL) { // Draw deleted tab if (m_removedTab) { int x_delta = m_removedTab->width - m_removedTab->width*(1.0-std::exp(-10.0 * m_ani_t / (double)ANI_REMOVING_TAB_TICKS)); x_delta = MID(0, x_delta, m_removedTab->width); gfx::Rect box2(box.x, box.y, x_delta, box.h); drawTab(g, box2, m_removedTab, 0, false); box.x += x_delta; box.w = 0; } } // Fill the gap to the right-side if (box.x < rect.x2()) { theme->draw_part_as_hline(g, gfx::Rect(box.x, box.y, rect.x2()-box.x, box.h), PART_TAB_FILLER); theme->draw_part_as_hline(g, gfx::Rect(box.x, box.y2(), rect.x2()-box.x, rect.y2()-box.y2()), PART_TAB_BOTTOM_NORMAL); } }