Merged in paimonen/apps/pullreq_nxwidgets (pull request #160)

NxWidgets improvements

* NxWidgets: fix garbage returned when CCycleButton::getValue() is called after removeAllOptions().

    It's a bit questionable whether returning 0 here is reasonable or
    if it would be better to assert(). But either is better than reading
    into random memory and returning a garbage value.

* NXWidgets CScrollingPanel: Don't draw outside the widget area.

    The port->move() function doesn't support clipping the
    copied area to the client area, so we have to manually
    calculate the part that can be moved without going outside
    the widget.

* CNxString: Add string + operator and ::format() function

* CNumericEdit: Add option to include unit name after the value

* NxWidgets: CNxWidget: Make useWidgetStyle() public

    Makes it easier to update styles when multiple controls are nested.

* NxWidgets: Add CLabelGrid control for displaying text in grid format.

Approved-by: GregoryN <gnutt@nuttx.org>
This commit is contained in:
Petteri Aimonen 2018-11-09 16:00:50 +00:00 committed by GregoryN
parent f5e399670f
commit 66d4ed9912
10 changed files with 549 additions and 10 deletions

View File

@ -0,0 +1,185 @@
/****************************************************************************
* NxWidgets/libnxwidgets/include/clabelgrid.hxx
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
* Petteri Aimonen <jpa@kapsi.fi>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX, NxWidgets, nor the names of its contributors
* me be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************
*
* Portions of this package derive from Woopsi (http://woopsi.org/) and
* portions are original efforts. It is difficult to determine at this
* point what parts are original efforts and which parts derive from Woopsi.
* However, in any event, the work of Antony Dzeryn will be acknowledged
* in all NxWidget files. Thanks Antony!
*
* Copyright (c) 2007-2011, Antony Dzeryn
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the names "Woopsi", "Simian Zombie" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Antony Dzeryn ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Antony Dzeryn BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#ifndef __INCLUDE_CLABELGRID_HXX
#define __INCLUDE_CLABELGRID_HXX
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <nuttx/nx/nxglib.h>
#include "cnxwidget.hxx"
#include "cwidgetstyle.hxx"
#include "tnxarray.hxx"
/****************************************************************************
* Pre-Processor Definitions
****************************************************************************/
/****************************************************************************
* Implementation Classes
****************************************************************************/
#if defined(__cplusplus)
namespace NXWidgets
{
/**
* Forward references
*/
class CWidgetControl;
class CRect;
class CLabel;
/**
* 2-dimensional grid of labels. Each row and column can have custom
* label styles applied.
*/
class CLabelGrid : public CNxWidget
{
protected:
int m_cols;
int m_rows;
TNxArray<CLabel*> m_labels;
TNxArray<int> m_colwidths;
TNxArray<int> m_rowheights;
/**
* Resize the widget to the new dimensions.
*
* @param width The new width.
* @param height The new height.
*/
virtual void onResize(nxgl_coord_t width, nxgl_coord_t height);
public:
/**
* Constructor for a grid of labels
*
* @param pWidgetControl The controlling widget for the display
* @param x The x coordinate of the text box, relative to its parent.
* @param y The y coordinate of the text box, relative to its parent.
* @param width The width of the textbox.
* @param height The height of the textbox.
* @param cols Number of colums in the grid.
* @param rows Number of rows in the grid.
*/
CLabelGrid(CWidgetControl *pWidgetControl, nxgl_coord_t x, nxgl_coord_t y,
nxgl_coord_t width, nxgl_coord_t height, int cols, int rows);
virtual inline ~CLabelGrid() { }
/**
* Get reference to the label at particular position of the grid.
*
* @param col Zero-based index of the column.
* @param row Zero-based index of the row.
* @returns Reference to CLabel.
*/
virtual CLabel &at(int col, int row);
/**
* Set width of a column.
*
* @param col Zero-based index of the column.
* @param width Width of column in pixels, or -1 to size automatically.
*/
void setColumnWidth(int col, int width);
/**
* Set height of a row.
*
* @param row Zero-based index of the row.
* @param height Height of row in pixels, or -1 to size automatically.
*/
void setRowHeight(int row, int height);
void setBackgroundColor(nxgl_mxpixel_t color);
void setBorderless(bool borderless);
void useWidgetStyle(const CWidgetStyle *style);
};
}
#endif // __cplusplus
#endif // __INCLUDE_CLABELGRID_HXX

View File

@ -0,0 +1,257 @@
/****************************************************************************
* NxWidgets/libnxwidgets/include/clabelgrid.hxx
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
* Petteri Aimonen <jpa@kapsi.fi>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX, NxWidgets, nor the names of its contributors
* me be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************
*
* Portions of this package derive from Woopsi (http://woopsi.org/) and
* portions are original efforts. It is difficult to determine at this
* point what parts are original efforts and which parts derive from Woopsi.
* However, in any event, the work of Antony Dzeryn will be acknowledged
* in all NxWidget files. Thanks Antony!
*
* Copyright (c) 2007-2011, Antony Dzeryn
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the names "Woopsi", "Simian Zombie" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Antony Dzeryn ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Antony Dzeryn BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "clabelgrid.hxx"
#include "clabel.hxx"
#include <assert.h>
#include <debug.h>
/****************************************************************************
* Pre-Processor Definitions
****************************************************************************/
/****************************************************************************
* CLabelGrid Method Implementations
****************************************************************************/
using namespace NXWidgets;
CLabelGrid::CLabelGrid(CWidgetControl* pWidgetControl, nxgl_coord_t x, nxgl_coord_t y,
nxgl_coord_t width, nxgl_coord_t height, int cols, int rows):
CNxWidget(pWidgetControl, x, y, width, height, 0, 0),
m_cols(cols), m_rows(rows)
{
setPermeable(true); // To allow easier relayouting
int cell_width = width / m_cols;
int cell_height = height / m_cols;
for (int row = 0; row < m_rows; row++)
{
m_rowheights.push_back(-1); // -1 signifies automatic sizing
}
for (int col = 0; col < m_cols; col++)
{
m_colwidths.push_back(-1);
}
for (int row = 0; row < m_rows; row++)
{
for (int col = 0; col < m_cols; col++)
{
CLabel *label = new CLabel(pWidgetControl, col * cell_width, row * cell_height,
cell_width, cell_height, "");
this->addWidget(label);
m_labels.push_back(label);
}
}
}
CLabel& CLabelGrid::at(int col, int row)
{
assert(col >= 0 && col < m_cols);
assert(row >= 0 && row < m_rows);
return *m_labels.at(row * m_cols + col);
}
void CLabelGrid::onResize(nxgl_coord_t width, nxgl_coord_t height)
{
this->disableDrawing();
// Count the number of automatically sized columns and rows and
// space available to them.
int autocols = 0;
int fixedwidth = 0;
for (int i = 0; i < m_cols; i++)
{
if (m_colwidths.at(i) < 0)
{
autocols++;
}
else
{
fixedwidth += m_colwidths.at(i);
}
}
int autorows = 0;
int fixedheight = 0;
for (int i = 0; i < m_rows; i++)
{
if (m_rowheights.at(i) < 0)
{
autorows++;
}
else
{
fixedheight += m_rowheights.at(i);
}
}
// Avoid divide by zero
if (autocols == 0)
autocols = 1;
if (autorows == 0)
autorows = 1;
// Divide the space among the rows and columns
int auto_width = (width - fixedwidth) / autocols;
int auto_height = (height - fixedheight) / autorows;
int y = 0;
for (int row = 0; row < m_rows; row++)
{
int h = m_rowheights.at(row);
if (h < 0)
{
h = auto_height;
}
int x = 0;
for (int col = 0; col < m_cols; col++)
{
int w = m_colwidths.at(col);
if (w < 0)
{
w = auto_width;
}
this->at(col, row).changeDimensions(x, y, w, h);
dbg("G %d %d: %d %d %d %d\n", col, row, x, y, w, h);
x += w;
}
y += h;
}
this->enableDrawing();
redraw();
}
void CLabelGrid::setColumnWidth(int col, int width)
{
m_colwidths.at(col) = width;
onResize(getWidth(), getHeight());
}
void CLabelGrid::setRowHeight(int row, int height)
{
m_rowheights.at(row) = height;
onResize(getWidth(), getHeight());
}
void CLabelGrid::setBackgroundColor(nxgl_mxpixel_t color)
{
CNxWidget::setBackgroundColor(color);
for (int row = 0; row < m_rows; row++)
{
for (int col = 0; col < m_cols; col++)
{
this->at(col, row).setBackgroundColor(color);
}
}
}
void CLabelGrid::setBorderless(bool borderless)
{
CNxWidget::setBorderless(borderless);
for (int row = 0; row < m_rows; row++)
{
for (int col = 0; col < m_cols; col++)
{
this->at(col, row).setBorderless(borderless);
}
}
}
void CLabelGrid::useWidgetStyle(const CWidgetStyle* style)
{
CNxWidget::useWidgetStyle(style);
for (int row = 0; row < m_rows; row++)
{
for (int col = 0; col < m_cols; col++)
{
this->at(col, row).useWidgetStyle(style);
}
}
}

View File

@ -51,7 +51,7 @@ CXXSRCS += cwidgeteventhandlerlist.cxx cwindoweventhandlerlist.cxx singletons.cx
CXXSRCS += cbutton.cxx cbuttonarray.cxx ccheckbox.cxx ccyclebutton.cxx
CXXSRCS += cglyphbutton.cxx cglyphsliderhorizontal.cxx cglyphsliderhorizontalgrip.cxx
CXXSRCS += cimage.cxx ckeypad.cxx clabel.cxx clatchbutton.cxx
CXXSRCS += cimage.cxx ckeypad.cxx clabel.cxx clabelgrid.cxx clatchbutton.cxx
CXXSRCS += clatchbuttonarray.cxx clistbox.cxx clistboxdataitem.cxx cmultilinetextbox.cxx
CXXSRCS += cnumericedit.cxx
CXXSRCS += cprogressbar.cxx cradiobutton.cxx cradiobuttongroup.cxx cscrollbarhorizontal.cxx

View File

@ -260,13 +260,25 @@ void CNumericEdit::setValue(int value)
m_value = value;
updateText();
}
void CNumericEdit::updateText()
{
char buf[10];
snprintf(buf, sizeof(buf), "%d", m_value);
CNxString text(buf);
CNxString text(buf);
text.append(m_unittext);
m_label->setText(text);
m_widgetEventHandlers->raiseValueChangeEvent();
redraw();
}
void CNumericEdit::setUnit(const CNxString& text)
{
m_unittext = text;
updateText();
}

View File

@ -77,6 +77,8 @@
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include "graphics/nxwidgets/cnxstring.hxx"
#include "graphics/nxwidgets/cstringiterator.hxx"
@ -804,3 +806,32 @@ FAR nxwidget_char_t *CNxString::getCharPointer(const int index) const
return &m_text[index];
}
CNxString CNxString::format(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
size_t len = vsnprintf(nullptr, 0, fmt, args) + 1;
va_end(args);
va_start(args, fmt);
CNxString result;
result.allocateMemory(len, false);
char *buf = reinterpret_cast<char*>(result.m_text);
vsnprintf(buf, len, fmt, args);
va_end(args);
if (sizeof(nxwidget_char_t) > sizeof(char))
{
// Expand the string to full width, beginning from the last
// character so that we don't overwrite characters before
// we have converted them.
for (int i = len - 1; i >= 0; i--)
{
result.m_text[i] = (nxwidget_char_t)buf[i];
}
}
result.m_stringLength = len - 1;
return result;
}

View File

@ -190,7 +190,23 @@ void CScrollingPanel::scroll(int32_t dx, int32_t dy)
TNxArray<CRect> revealedRects;
CGraphicsPort *port = m_widgetControl->getGraphicsPort();
port->move(getX(), getY(), dx, dy, rect.getWidth(), rect.getHeight());
if (dx >= 0 && dy >= 0)
{
port->move(getX(), getY(), dx, dy, rect.getWidth() - dx, rect.getHeight() - dy);
}
else if (dx <= 0 && dy >= 0)
{
port->move(getX() - dx, getY(), dx, dy, rect.getWidth() + dx, rect.getHeight() - dy);
}
else if (dx >= 0 && dy <= 0)
{
port->move(getX(), getY() - dy, dx, dy, rect.getWidth() - dx, rect.getHeight() + dy);
}
else if (dx <= 0 && dy <= 0)
{
port->move(getX() - dx, getY() - dy, dx, dy, rect.getWidth() + dx, rect.getHeight() + dy);
}
if (dx > 0)
{
@ -226,6 +242,7 @@ void CScrollingPanel::scroll(int32_t dx, int32_t dy)
for (int i = 0; i < revealedRects.size(); ++i)
{
CRect &rrect = revealedRects[i];
rrect.clipToIntersect(rect);
ginfo("Redrawing %d,%d,%d,%d after scroll\n",
rrect.getX(), rrect.getY(),

View File

@ -279,7 +279,8 @@ namespace NXWidgets
inline const uint32_t getValue(void) const
{
return getSelectedOption()->getValue();
const NXWidgets::CListDataItem *item = getSelectedOption();
return item ? item->getValue() : 0;
}
/**

View File

@ -119,6 +119,7 @@ namespace NXWidgets
CButton *m_button_minus;
CButton *m_button_plus;
CNxTimer *m_timer;
CNxString m_unittext;
int m_value;
int m_minimum;
int m_maximum;
@ -150,6 +151,8 @@ namespace NXWidgets
inline CNumericEdit(const CNumericEdit &num) : CNxWidget(num) { };
void updateText();
public:
/**
@ -193,6 +196,11 @@ namespace NXWidgets
virtual void setFont(CNxFont *font);
/**
* Sets the text to display after the numeric value.
*/
void setUnit(const CNxString& text);
inline int getValue() const { return m_value; }
void setValue(int value);

View File

@ -477,6 +477,25 @@ namespace NXWidgets
CNxString &operator=(nxwidget_char_t letter);
/**
* Overloaded sum operator. Appends the string to current string.
*/
inline CNxString &operator+=(const CNxString &other)
{
append(other);
return *this;
}
/**
* Overloaded sum operator. Concatenates two strings.
*/
inline CNxString operator+(const CNxString &other)
{
CNxString result = *this;
result.append(other);
return result;
}
/**
* Compares this string to the argument.
*
@ -488,6 +507,15 @@ namespace NXWidgets
*/
int compareTo(const CNxString &string) const;
/**
* snprintf()-style string formatting. Automatically allocates correct
* amount of memory.
*
* @param fmt printf format string.
* @return New CNxString instance.
*/
static CNxString format(const char *fmt, ...);
};
}

View File

@ -207,12 +207,6 @@ namespace NXWidgets
WidgetBorderSize m_borderSize; /**< Size of the widget borders. */
/**
* Use the provided widget style
*/
void useWidgetStyle(const CWidgetStyle *style);
/**
* Draw the area of this widget that falls within the clipping region.
* Called by the redraw() function to draw all visible regions.
@ -803,6 +797,12 @@ namespace NXWidgets
inline const CWidgetStyle *getWidgetStyle() const { return &m_style; }
/**
* Use the provided widget style
*/
void useWidgetStyle(const CWidgetStyle *style);
/**
* Sets this widget's border state.
*