diff --git a/src/gui/components/Makefile.am b/src/gui/components/Makefile.am index 2c78d799a..500d2b17a 100644 --- a/src/gui/components/Makefile.am +++ b/src/gui/components/Makefile.am @@ -28,6 +28,7 @@ libneutrino_gui_components_a_SOURCES = \ cc_detailsline.cpp \ cc_frm_button.cpp \ cc_frm.cpp \ + cc_frm_clock.cpp \ cc_frm_header.cpp \ cc_frm_icons.cpp \ cc_frm_window.cpp \ diff --git a/src/gui/components/cc_frm_clock.cpp b/src/gui/components/cc_frm_clock.cpp new file mode 100644 index 000000000..d1f81f53f --- /dev/null +++ b/src/gui/components/cc_frm_clock.cpp @@ -0,0 +1,302 @@ +/* + Based up Neutrino-GUI - Tuxbox-Project + Copyright (C) 2001 by Steffen Hehn 'McClean' + + Generic GUI-related component. + Copyright (C) 2013, Thilo Graf 'dbt' + + License: GPL + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "cc_frm_clock.h" +#include +#include +#include +#include + +using namespace std; + +CComponentsFrmClock::CComponentsFrmClock( const int x_pos, const int y_pos, const int w, const int h, + const char* format_str, bool has_shadow, + fb_pixel_t color_frame, fb_pixel_t color_body, fb_pixel_t color_shadow) + +{ + initVarClock(); + + x = x_pos; + y = y_pos; + width = w; + height = h; + shadow = has_shadow; + shadow_w = SHADOW_OFFSET; + col_frame = color_frame; + col_body = color_body; + col_shadow = color_shadow; + + cl_format_str = format_str; +} + +void CComponentsFrmClock::initVarClock() +{ + initVarForm(); + cc_item_type = CC_ITEMTYPE_FRM_CLOCK; + corner_rad = RADIUS_SMALL; + + cl_font_type = SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO; + cl_font = NULL; + cl_format_str = "%H:%M"; + cl_align = CC_ALIGN_VER_CENTER | CC_ALIGN_HOR_CENTER; +// cl_force_segment_paint = false; + + cl_thread = 0; + cl_interval = 1; +} + +CComponentsFrmClock::~CComponentsFrmClock() +{ + cleanCCForm(); + if(cl_thread) + pthread_cancel(cl_thread); + cl_thread = 0; +} + +void CComponentsFrmClock::initTimeString() +{ + time_t tm = time(0); + strftime((char*) &cl_timestr, sizeof(cl_timestr), cl_format_str, localtime(&tm)); +} + +// How does it works? +// We don't paint complete date or time string at once, because of individual possible formats, +// so we split timestring and assign only one char to one lable (segment) + +// x/y width +// +--------------------------+ +// ||lbl0|lbl1|lbl2|lbl3|lbl4|| +// || | | | | ||height +// || | | | | || +// +--------------------------+ + +// So every item (lable or segment) contains only one char depending on specified format. eg: format %H:%M gives 5 items. +// The effort is slightly greater and it's necessary to avoid flicker effect, but it's more flexible. + +void CComponentsFrmClock::initCCLockItems() +{ + initTimeString(); + string s_time = cl_timestr; + + cl_font = g_Font[cl_font_type]; + + //get minimal required height, width from raw text + int min_text_w = cl_font->getRenderWidth(s_time, true);; + int min_text_h = cl_font->getHeight(); + height = max(height, min_text_h); + width = max(width, min_text_w); + + int cl_x = 0; + int cl_h = min_text_h; + int cl_y = 0; + int w_lbl_tmp = 0; + + //create label objects and add to container, ensure count of items = count of chars (one char = one segment) + if (v_cc_items.size() != s_time.size()){ + + //clean up possible old items before add new items + clearCCItems(); + + //create new empty label objects, set some general properties and add to container + for (size_t i = 0; i < s_time.size(); i++){ + CComponentsLabel * lbl = new CComponentsLabel(); + addCCItem(lbl); + + //background paint of item is not required + lbl->doPaintBg(false); + + //set corner properties of label item + lbl->setCornerRadius(corner_rad-fr_thickness); + lbl->setCornerType(corner_type); + } + } + + //modifie available lable items with current segment chars + for (size_t i = 0; i < v_cc_items.size(); i++) + { + //v_cc_items are only available as CComponent-items here, so we must cast them before + CComponentsLabel *lbl = static_cast (v_cc_items[i]); + + //add rounded corners only to 1st and last segment + if (corner_type) { + if (i == 0) + lbl->setCornerType(corner_type & CORNER_LEFT);// 1st label item + else if (i == v_cc_items.size()-1) + lbl->setCornerType(corner_type & CORNER_RIGHT);// last label item + else + lbl->setCornerType(0);// inner items + } + + //extract timestring segment (char) + string stmp = s_time.substr(i, 1); + + //get width of current segment + int wtmp = cl_font->getRenderWidth(stmp, true); + + //set size, text, color of current item + lbl->setDimensionsAll(cl_x, cl_y, wtmp, cl_h); + lbl->setTextColor(COL_MENUCONTENT); + lbl->setText(stmp, CTextBox::CENTER, cl_font); + + //use matching height for digits for better vertical centerring into form + CTextBox* ctb = lbl->getCTextBoxObject(); + if (ctb) + ctb->setFontUseDigitHeight(); + + //ensure paint of text and label bg on changed text or painted form background + bool force_txt_and_bg = (lbl->textChanged() || this->paint_bg); + lbl->forceTextPaint(force_txt_and_bg); + lbl->doPaintTextBoxBg(force_txt_and_bg); + + //set xpos of item + cl_x += wtmp; + + lbl->setWidth(wtmp); + + //set current width for form + w_lbl_tmp += wtmp; + } + + //set required width + width = max(width, w_lbl_tmp); + + initSegmentAlign(&w_lbl_tmp, &min_text_h); +} + +//handle alignment +void CComponentsFrmClock::initSegmentAlign(int* segment_width, int* segment_height) +{ + int wadd = 0; + int hadd = 0; + int* w_lbl_tmp = segment_width; + int* min_text_h = segment_height; + + //use first item as reference and set x and y position to the 1st segement item with definied alignment + if (cl_align & CC_ALIGN_RIGHT){ + wadd = width-*w_lbl_tmp; + v_cc_items[0]->setXPos(wadd); + } + else if (cl_align & CC_ALIGN_LEFT){ + v_cc_items[0]->setXPos(wadd); + } + else if (cl_align & CC_ALIGN_HOR_CENTER){ + hadd = height/2-*min_text_h/2; + v_cc_items[0]->setYPos(hadd); + } + + if (cl_align & CC_ALIGN_TOP){ + v_cc_items[0]->setYPos(hadd); + } + else if (cl_align & CC_ALIGN_BOTTOM){ + hadd = height-*min_text_h; + v_cc_items[0]->setYPos(hadd); + } + else if (cl_align & CC_ALIGN_VER_CENTER){ + wadd = width/2-*w_lbl_tmp/2; + v_cc_items[0]->setXPos(wadd); + } + + //set all evaluated position values to all other segement items + for (size_t i = 1; i < v_cc_items.size(); i++){ + wadd += v_cc_items[i-1]->getWidth(); + v_cc_items[i]->setPos(wadd, hadd); + } +} + +//thread handle +void* CComponentsFrmClock::initClockThread(void *arg) +{ + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0); + pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS,0); + + CComponentsFrmClock *clock = static_cast(arg); + + //ensure paint of segements on first paint + clock->paint(); + + //start loop for paint + while(1) { + sleep(clock->cl_interval); + + //paint segements, but wihtout saved backgrounds + clock->paint(CC_SAVE_SCREEN_NO); + } + return 0; +} + +//start up ticking clock with own thread, return true on succses +bool CComponentsFrmClock::Start() +{ + void *ptr = static_cast(this); + + if(!cl_thread) { + int res1 = pthread_create (&cl_thread, NULL, initClockThread, ptr) ; + int res2 = pthread_detach(cl_thread); + + if (res1 != 0){ + printf("[CComponentsFrmClock] [%s] pthread_create %s\n", __FUNCTION__, strerror(errno)); + return false; + } + if (res2 != 0){ + printf("[CComponentsFrmClock] [%s] pthread_detach %s\n", __FUNCTION__, strerror(errno)); + return false; + } + } + return true; +} + +//stop ticking clock and kill thread, return true on succses +bool CComponentsFrmClock::Stop() +{ + int res = 0; + + if(cl_thread) + res = pthread_cancel(cl_thread); + + if (res != 0){ + printf("[CComponentsFrmClock] [%s] pthread_cancel %s\n", __FUNCTION__, strerror(errno)); + return false; + } + + cl_thread = 0; + return true; +} + + +void CComponentsFrmClock::paint(bool do_save_bg) +{ + //prepare items before paint + initCCLockItems(); + + //paint form contents + paintForm(do_save_bg); +} diff --git a/src/gui/components/cc_frm_clock.h b/src/gui/components/cc_frm_clock.h new file mode 100644 index 000000000..176d17cad --- /dev/null +++ b/src/gui/components/cc_frm_clock.h @@ -0,0 +1,104 @@ +/* + Based up Neutrino-GUI - Tuxbox-Project + Copyright (C) 2001 by Steffen Hehn 'McClean' + + Classes for generic GUI-related components. + Copyright (C) 2012, 2013, Thilo Graf 'dbt' + + License: GPL + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __CC_CLOCK__ +#define __CC_CLOCK__ + + +#include "config.h" +#include "cc.h" +#include "cc_frm.h" + + +//! Sub class of CComponents. Show clock with digits on screen. +/*! +Usable as simple fixed display or as ticking clock. +*/ + +class CComponentsFrmClock : public CComponentsForm +{ + private: + +// bool cl_force_segment_paint; + + protected: + ///thread + pthread_t cl_thread; + ///refresh interval in seconds + int cl_interval; + ///init function to start clock in own thread + static void* initClockThread(void *arg); + + ///raw time chars + char cl_timestr[20]; + + ///font + int cl_font_type; + ///fontrenderer object + Font *cl_font; + ///time format + const char* cl_format_str; + ///time string align, default allign is ver and hor centered + int cl_align; + + ///initialize all attributes and required objects + void initVarClock(); + + ///initialize clock contents + void initCCLockItems(); + ///initialize timestring, called in initCCLockItems() + void initTimeString(); + ///initialize of general alignment of timestring segments within form area + void initSegmentAlign(int* segment_width, int* segment_height); + + public: + CComponentsFrmClock( const int x_pos, const int y_pos, const int w, const int h, + const char* format_str = "%H:%M", bool has_shadow = CC_SHADOW_OFF, + fb_pixel_t color_frame = COL_LIGHT_GRAY, fb_pixel_t color_body = COL_MENUCONTENT_PLUS_0, fb_pixel_t color_shadow = COL_MENUCONTENTDARK_PLUS_0); + ~CComponentsFrmClock(); + + ///set font type for segments + void setClockFontType(const int& font_type){cl_font_type = font_type;}; + + ///set alignment of timestring, possible modes see align types in cc_types.h + void setClockAlignment(int align_type){cl_align = align_type;}; + + ///use string expession: "%H:%M" = 12:22, "%H:%M:%S" = 12:22:12 + void setClockFormat(const char* format_str){cl_format_str = format_str;}; + + ///start ticking clock thread, returns true on success, if false causes log output + bool Start(); + ///stop ticking clock thread, returns true on success, if false causes log output + bool Stop(); + ///returns true, if clock is running in thread + bool isClockRun() const {return cl_thread == 0 ? false:true;}; + ///set refresh interval in seconds, default value=1 (=1 sec) + void setClockIntervall(const int& seconds){cl_interval = seconds;}; + + ///show clock on screen + void paint(bool do_save_bg = CC_SAVE_SCREEN_YES); +}; + +#endif diff --git a/src/gui/components/cc_types.h b/src/gui/components/cc_types.h index 60a842ab4..a72b98cbc 100644 --- a/src/gui/components/cc_types.h +++ b/src/gui/components/cc_types.h @@ -40,6 +40,7 @@ typedef enum CC_ITEMTYPE_SHAPE_CIRCLE, CC_ITEMTYPE_PIP, CC_ITEMTYPE_FRM, + CC_ITEMTYPE_FRM_CLOCK, CC_ITEMTYPE_FRM_HEADER, CC_ITEMTYPE_FRM_ICONFORM, CC_ITEMTYPE_FRM_WINDOW, diff --git a/src/gui/test_menu.cpp b/src/gui/test_menu.cpp index d96d93236..4e06919a9 100644 --- a/src/gui/test_menu.cpp +++ b/src/gui/test_menu.cpp @@ -71,6 +71,7 @@ CTestMenu::CTestMenu() iconform = NULL; window = NULL; button = NULL; + clock = clock_r = NULL; } CTestMenu::~CTestMenu() @@ -84,6 +85,8 @@ CTestMenu::~CTestMenu() delete iconform; delete window; delete button; + delete clock; + delete clock_r; } int CTestMenu::exec(CMenuTarget* parent, const std::string &actionKey) @@ -527,6 +530,40 @@ int CTestMenu::exec(CMenuTarget* parent, const std::string &actionKey) return res; } + else if (actionKey == "running_clock"){ + if (clock_r == NULL){ + clock_r = new CComponentsFrmClock(100, 50, 0, 50, "%H.%M:%S"); + clock_r->setClockFontType(SNeutrinoSettings::FONT_TYPE_INFOBAR_CHANNAME); + clock_r->setClockIntervall(1); +// clock_r->doPaintBg(false); + } + + if (!clock_r->isClockRun()){ + if (clock_r->Start()) + return menu_return::RETURN_EXIT_ALL;; + } + else if (clock_r->isClockRun()){ + if (clock_r->Stop()){ + clock_r->hide(); + delete clock; + clock = NULL; + return menu_return::RETURN_EXIT_ALL;; + } + } + } + else if (actionKey == "clock"){ + if (clock == NULL){ + clock = new CComponentsFrmClock(100, 50, 0, 50, "%H:%M"); + clock->setClockFontType(SNeutrinoSettings::FONT_TYPE_INFOBAR_CHANNAME); + } + + if (!clock->isPainted()) + clock->paint(); + else + clock->hide(); + + return res; + } return showTestMenu(); @@ -563,6 +600,8 @@ int CTestMenu::showTestMenu() void CTestMenu::showCCTests(CMenuWidget *widget) { widget->addIntroItems(); + widget->addItem(new CMenuForwarderNonLocalized("Running Clock", true, NULL, this, "running_clock")); + widget->addItem(new CMenuForwarderNonLocalized("Clock", true, NULL, this, "clock")); widget->addItem(new CMenuForwarderNonLocalized("Button", true, NULL, this, "button")); widget->addItem(new CMenuForwarderNonLocalized("Circle", true, NULL, this, "circle")); widget->addItem(new CMenuForwarderNonLocalized("Square", true, NULL, this, "square")); diff --git a/src/gui/test_menu.h b/src/gui/test_menu.h index d51afa955..57bc63d1b 100644 --- a/src/gui/test_menu.h +++ b/src/gui/test_menu.h @@ -34,6 +34,7 @@ #include #include #include +#include #define TEST_MENU #include @@ -50,6 +51,7 @@ class CTestMenu : public CMenuTarget CComponentsIconForm *iconform; CComponentsWindow *window; CComponentsButton *button; + CComponentsFrmClock *clock ,*clock_r; int width, selected; int showTestMenu();