chore: pull libopenui into the EdgeTX repository
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
BreakBeforeBraces: Linux
|
||||
BreakConstructorInitializers: AfterColon
|
||||
...
|
||||
@@ -0,0 +1 @@
|
||||
src/thirdparty/stb/
|
||||
@@ -0,0 +1,7 @@
|
||||
[submodule "thirdparty/stb"]
|
||||
path = thirdparty/stb
|
||||
url = https://github.com/nothings/stb.git
|
||||
[submodule "thirdparty/lvgl"]
|
||||
path = thirdparty/lvgl
|
||||
url = https://github.com/EdgeTX/lvgl.git
|
||||
branch = release/v8.2
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<option name="RIGHT_MARGIN" value="160" />
|
||||
<Objective-C>
|
||||
<option name="INDENT_C_STRUCT_MEMBERS" value="2" />
|
||||
<option name="INDENT_VISIBILITY_KEYWORDS" value="2" />
|
||||
<option name="FUNCTION_BRACE_PLACEMENT" value="2" />
|
||||
<option name="SUPERCLASS_LIST_BEFORE_COLON" value="0" />
|
||||
<option name="SPACE_AFTER_POINTER_IN_DECLARATION" value="true" />
|
||||
<option name="SPACE_AFTER_REFERENCE_IN_DECLARATION" value="true" />
|
||||
</Objective-C>
|
||||
<codeStyleSettings language="CMake">
|
||||
<option name="SPACE_BEFORE_IF_PARENTHESES" value="false" />
|
||||
<option name="SPACE_BEFORE_WHILE_PARENTHESES" value="false" />
|
||||
<option name="SPACE_BEFORE_FOR_PARENTHESES" value="false" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="8" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="ObjectiveC">
|
||||
<option name="CLASS_BRACE_STYLE" value="2" />
|
||||
<option name="ELSE_ON_NEW_LINE" value="true" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="8" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
# libopenui
|
||||
C++ UI Library primarily used in EdgeTX for Colour LCD targets.
|
||||
|
||||
Was forked from [OpenTX/libopenui](https://github.com/opentx/libopenui) and detached so that contributors can easily work on both if they wish to do so.
|
||||
@@ -0,0 +1,57 @@
|
||||
if(HARDWARE_KEYS)
|
||||
add_definitions(-DHARDWARE_KEYS)
|
||||
endif()
|
||||
|
||||
if(HARWARE_TOUCH)
|
||||
add_definitions(-DHARDWARE_TOUCH)
|
||||
endif()
|
||||
|
||||
set(LIBOPENUI_SRC
|
||||
libopenui_file.cpp
|
||||
bitmapbuffer.cpp
|
||||
window.cpp
|
||||
layer.cpp
|
||||
form.cpp
|
||||
button.cpp
|
||||
button_matrix.cpp
|
||||
static.cpp
|
||||
checkbox.cpp
|
||||
carousel.cpp
|
||||
slider.cpp
|
||||
mainwindow.cpp
|
||||
menu.cpp
|
||||
menutoolbar.cpp
|
||||
choice.cpp
|
||||
choiceex.cpp
|
||||
filechoice.cpp
|
||||
numberedit.cpp
|
||||
textedit.cpp
|
||||
progress.cpp
|
||||
table.cpp
|
||||
modal_window.cpp
|
||||
dialog.cpp
|
||||
keyboard_text.cpp
|
||||
keyboard_number.cpp
|
||||
keyboard_base.cpp
|
||||
# LVGL widgets
|
||||
widgets/window_base.c
|
||||
widgets/simple_btn.c
|
||||
widgets/field_edit.c
|
||||
widgets/edgetx_table.c
|
||||
)
|
||||
|
||||
foreach(LIBOPENUI_FILE ${LIBOPENUI_SRC})
|
||||
set(LIBOPENUI_SRC_FILES ${LIBOPENUI_SRC_FILES} ${LIBOPENUI_SRC_DIR}/src/${LIBOPENUI_FILE})
|
||||
endforeach()
|
||||
|
||||
set(SRC ${SRC} ${LIBOPENUI_SRC_FILES}
|
||||
${LIBOPENUI_SRC_DIR}/thirdparty/lz4/lz4.c
|
||||
)
|
||||
|
||||
# add_library(libopenui_native OBJECT ${LIBOPENUI_SRC_FILES})
|
||||
# add_library(libopenui_stm32 OBJECT ${LIBOPENUI_SRC_FILES})
|
||||
|
||||
# Dirty hack to include FatFs into libopenui
|
||||
# TODO: this must go away
|
||||
#target_include_directories(libopenui PRIVATE
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/../../FatFs)
|
||||
+223
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "form.h"
|
||||
#include "strhelpers.h"
|
||||
|
||||
class BaseNumberEdit: public FormField
|
||||
{
|
||||
public:
|
||||
BaseNumberEdit(Window* parent, const rect_t& rect, int vmin, int vmax,
|
||||
std::function<int()> getValue,
|
||||
std::function<void(int)> setValue = nullptr,
|
||||
WindowFlags windowFlags = 0, LcdFlags textFlags = 0,
|
||||
LvglCreate objConstruct = nullptr) :
|
||||
FormField(parent, rect, windowFlags, textFlags, objConstruct),
|
||||
vmin(vmin),
|
||||
vmax(vmax),
|
||||
_getValue(std::move(getValue)),
|
||||
_setValue(std::move(setValue))
|
||||
{
|
||||
}
|
||||
|
||||
void setMin(int value)
|
||||
{
|
||||
vmin = value;
|
||||
}
|
||||
|
||||
void setMax(int value)
|
||||
{
|
||||
vmax = value;
|
||||
}
|
||||
|
||||
void setDefault(int value)
|
||||
{
|
||||
vdefault = value;
|
||||
}
|
||||
|
||||
int32_t getMin() const
|
||||
{
|
||||
return vmin;
|
||||
}
|
||||
|
||||
int32_t getMax() const
|
||||
{
|
||||
return vmax;
|
||||
}
|
||||
|
||||
int32_t getDefault() const
|
||||
{
|
||||
return vdefault;
|
||||
}
|
||||
|
||||
void setStep(int value)
|
||||
{
|
||||
step = value;
|
||||
}
|
||||
|
||||
int32_t getStep() const
|
||||
{
|
||||
return step;
|
||||
}
|
||||
|
||||
void setFastStep(int value)
|
||||
{
|
||||
fastStep = value;
|
||||
}
|
||||
|
||||
int32_t getFastStep() const
|
||||
{
|
||||
return fastStep;
|
||||
}
|
||||
|
||||
void setAccelFactor(int value)
|
||||
{
|
||||
accelFactor = value;
|
||||
}
|
||||
|
||||
int32_t getAccelFactor() const
|
||||
{
|
||||
return accelFactor;
|
||||
}
|
||||
|
||||
void setValue(int value)
|
||||
{
|
||||
auto newValue = limit(vmin, value, vmax);
|
||||
if (newValue != currentValue) {
|
||||
currentValue = newValue;
|
||||
if (instantChange && _setValue != nullptr) {
|
||||
_setValue(currentValue);
|
||||
}
|
||||
}
|
||||
if (lvobj != nullptr) {
|
||||
std::string str;
|
||||
if (displayFunction != nullptr) {
|
||||
str = displayFunction(currentValue);
|
||||
} else {
|
||||
str = formatNumberAsString(currentValue, textFlags, 0, prefix.c_str(),
|
||||
suffix.c_str());
|
||||
}
|
||||
lv_textarea_set_text(lvobj, str.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void setPrefix(std::string value)
|
||||
{
|
||||
prefix = std::move(value);
|
||||
update();
|
||||
}
|
||||
|
||||
void setSuffix(std::string value)
|
||||
{
|
||||
suffix = std::move(value);
|
||||
update();
|
||||
}
|
||||
|
||||
void setZeroText(std::string value)
|
||||
{
|
||||
zeroText = std::move(value);
|
||||
update();
|
||||
}
|
||||
|
||||
void enableInstantChange(bool value)
|
||||
{
|
||||
instantChange = value;
|
||||
}
|
||||
|
||||
void disableInstantChange()
|
||||
{
|
||||
enableInstantChange(false);
|
||||
}
|
||||
|
||||
void setSetValueHandler(std::function<void(int)> handler)
|
||||
{
|
||||
_setValue = std::move(handler);
|
||||
}
|
||||
|
||||
void setGetValueHandler(std::function<int()> handler)
|
||||
{
|
||||
_getValue = std::move(handler);
|
||||
}
|
||||
|
||||
int32_t getValue() const
|
||||
{
|
||||
return (editMode && !instantChange) ? currentValue
|
||||
: _getValue != nullptr ? _getValue()
|
||||
: 0;
|
||||
}
|
||||
|
||||
void setEditMode(bool newEditMode) override
|
||||
{
|
||||
auto previousEditMode = editMode;
|
||||
FormField::setEditMode(newEditMode);
|
||||
if (!instantChange) {
|
||||
if (!previousEditMode && newEditMode) {
|
||||
if (_getValue != nullptr) currentValue = _getValue();
|
||||
}
|
||||
else if (previousEditMode && !newEditMode) {
|
||||
if (_setValue != nullptr) _setValue(currentValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setDisplayHandler(std::function<std::string(int value)> function)
|
||||
{
|
||||
displayFunction = std::move(function);
|
||||
update();
|
||||
}
|
||||
|
||||
virtual void update()
|
||||
{
|
||||
if (_getValue == nullptr) return;
|
||||
auto newValue = _getValue();
|
||||
if (newValue != currentValue) {
|
||||
currentValue = newValue;
|
||||
}
|
||||
if (lvobj != nullptr) {
|
||||
std::string str;
|
||||
if (displayFunction != nullptr) {
|
||||
str = displayFunction(currentValue);
|
||||
} else {
|
||||
str = formatNumberAsString(currentValue, textFlags, 0, prefix.c_str(),
|
||||
suffix.c_str());
|
||||
}
|
||||
lv_textarea_set_text(lvobj, str.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
virtual void paint(BitmapBuffer* dc) override {};
|
||||
|
||||
protected:
|
||||
int vdefault = 0;
|
||||
int vmin;
|
||||
int vmax;
|
||||
int step = 1;
|
||||
int fastStep = 10;
|
||||
int accelFactor = 4;
|
||||
int currentValue;
|
||||
bool instantChange = true;
|
||||
std::string prefix;
|
||||
std::string suffix;
|
||||
std::string zeroText;
|
||||
std::function<int()> _getValue;
|
||||
std::function<void(int)> _setValue;
|
||||
std::function<std::string(int)> displayFunction;
|
||||
};
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
// A set of bitfield handling macros
|
||||
|
||||
template <typename T>
|
||||
inline T bfBit(uint8_t n)
|
||||
{
|
||||
return T(1) << n;
|
||||
}
|
||||
|
||||
#define BFBIT_FLIP(y, mask) ( y ^= (mask) )
|
||||
|
||||
//! Create a bitmask of length 'len'.
|
||||
template <typename T>
|
||||
inline T bfBitmask(uint8_t len)
|
||||
{
|
||||
return bfBit<T>(len) - 1;
|
||||
}
|
||||
|
||||
//! Create a bitfield mask of length 'len' starting at bit 'start'.
|
||||
template <typename T>
|
||||
inline T bfMask(uint8_t start, uint8_t len)
|
||||
{
|
||||
return bfBitmask<T>(len) << start;
|
||||
}
|
||||
|
||||
//! Prepare a bitmask for insertion or combining.
|
||||
template <typename T>
|
||||
inline T bfPrep(T x, uint8_t start, uint8_t len)
|
||||
{
|
||||
return (x & bfBitmask<T>(len)) << start;
|
||||
}
|
||||
|
||||
//! Extract a bitfield of length 'len' starting at bit 'start' from 'y'.
|
||||
template <typename T>
|
||||
inline T bfGet(T y, uint8_t start, uint8_t len)
|
||||
{
|
||||
return ((y)>>(start)) & bfBitmask<T>(len);
|
||||
}
|
||||
|
||||
//! Insert 'len' bits of 'x 'into 'y', starting at bit 'start' from 'y'.
|
||||
template <class T>
|
||||
inline T bfSet(T to, T from, uint8_t start, uint8_t len)
|
||||
{
|
||||
return (to & ~bfMask<T>(start, len)) | bfPrep<T>(from, start, len);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T bfBitGet(T y, T mask)
|
||||
{
|
||||
return (y & mask);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T bfSingleBitGet(T y, uint8_t i)
|
||||
{
|
||||
return bfBitGet(y, bfBit<T>(i));
|
||||
}
|
||||
|
||||
+1825
File diff suppressed because it is too large
Load Diff
+475
@@ -0,0 +1,475 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "libopenui_types.h"
|
||||
#include "libopenui_defines.h"
|
||||
#include "libopenui_depends.h"
|
||||
#include "libopenui_helpers.h"
|
||||
#include "debug.h"
|
||||
|
||||
constexpr uint8_t SOLID = 0xFF;
|
||||
constexpr uint8_t DOTTED = 0x55;
|
||||
constexpr uint8_t STASHED = 0x33;
|
||||
|
||||
#define MOVE_OFFSET() coord_t offsetX = this->offsetX; x += offsetX; this->offsetX = 0; coord_t offsetY = this->offsetY; y += offsetY; this->offsetY = 0
|
||||
#define APPLY_OFFSET() x += this->offsetX; y += this->offsetY
|
||||
#define RESTORE_OFFSET() this->offsetX = offsetX, this->offsetY = offsetY
|
||||
|
||||
#if defined(LCD_VERTICAL_INVERT) && 0
|
||||
#define MOVE_PIXEL_RIGHT(p, count) p -= count
|
||||
#else
|
||||
#define MOVE_PIXEL_RIGHT(p, count) p += count
|
||||
#endif
|
||||
|
||||
#define MOVE_TO_NEXT_RIGHT_PIXEL(p) MOVE_PIXEL_RIGHT(p, 1)
|
||||
|
||||
#define USE_STB
|
||||
|
||||
enum BitmapFormats
|
||||
{
|
||||
BMP_INVALID = -1,
|
||||
BMP_8BIT = 0,
|
||||
BMP_RGB565,
|
||||
BMP_ARGB4444
|
||||
};
|
||||
|
||||
struct _lv_draw_ctx_t;
|
||||
typedef _lv_draw_ctx_t lv_draw_ctx_t;
|
||||
|
||||
struct _lv_obj_t;
|
||||
typedef _lv_obj_t lv_obj_t;
|
||||
|
||||
template<class T>
|
||||
class BitmapBufferBase
|
||||
{
|
||||
public:
|
||||
BitmapBufferBase(uint8_t format, uint16_t width, uint16_t height, T * data):
|
||||
format(format),
|
||||
_width(width),
|
||||
_height(height),
|
||||
xmax(width),
|
||||
ymax(height),
|
||||
data(data),
|
||||
data_end(data + (width * height))
|
||||
{
|
||||
}
|
||||
|
||||
BitmapBufferBase(uint8_t format, T * data):
|
||||
format(format),
|
||||
_width(*((uint16_t*)data)),
|
||||
_height(*(((uint16_t*)data) + 1)),
|
||||
xmax(_width),
|
||||
ymax(_height),
|
||||
data(data + 2),
|
||||
data_end(data + 2 + (_width * _height))
|
||||
{
|
||||
}
|
||||
|
||||
inline void clearClippingRect()
|
||||
{
|
||||
xmin = 0;
|
||||
xmax = _width;
|
||||
ymin = 0;
|
||||
ymax = _height;
|
||||
}
|
||||
|
||||
inline void setClippingRect(coord_t xmin, coord_t xmax, coord_t ymin, coord_t ymax)
|
||||
{
|
||||
this->xmin = xmin;
|
||||
this->xmax = xmax;
|
||||
this->ymin = ymin;
|
||||
this->ymax = ymax;
|
||||
}
|
||||
|
||||
inline void getClippingRect(coord_t & xmin, coord_t & xmax, coord_t & ymin, coord_t & ymax)
|
||||
{
|
||||
xmin = this->xmin;
|
||||
xmax = this->xmax;
|
||||
ymin = this->ymin;
|
||||
ymax = this->ymax;
|
||||
}
|
||||
|
||||
inline void setOffset(coord_t offsetX, coord_t offsetY)
|
||||
{
|
||||
this->offsetX = offsetX;
|
||||
this->offsetY = offsetY;
|
||||
}
|
||||
|
||||
inline void clearOffset()
|
||||
{
|
||||
setOffset(0, 0);
|
||||
}
|
||||
|
||||
inline void reset()
|
||||
{
|
||||
clearOffset();
|
||||
clearClippingRect();
|
||||
}
|
||||
|
||||
coord_t getOffsetX() const
|
||||
{
|
||||
return offsetX;
|
||||
}
|
||||
|
||||
coord_t getOffsetY() const
|
||||
{
|
||||
return offsetY;
|
||||
}
|
||||
|
||||
inline uint8_t getFormat() const
|
||||
{
|
||||
return format;
|
||||
}
|
||||
|
||||
inline uint16_t width() const
|
||||
{
|
||||
return _width;
|
||||
}
|
||||
|
||||
inline uint16_t height() const
|
||||
{
|
||||
return _height;
|
||||
}
|
||||
|
||||
inline T * getData() const
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
uint32_t getDataSize() const
|
||||
{
|
||||
return _width * _height * sizeof(T);
|
||||
}
|
||||
|
||||
inline const pixel_t * getPixelPtrAbs(coord_t x, coord_t y) const
|
||||
{
|
||||
#if defined(LCD_VERTICAL_INVERT) && 0
|
||||
x = _width - x - 1;
|
||||
y = _height - y - 1;
|
||||
#endif
|
||||
return &data[y * _width + x];
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t format;
|
||||
coord_t _width;
|
||||
coord_t _height;
|
||||
coord_t xmin = 0;
|
||||
coord_t xmax;
|
||||
coord_t ymin = 0;
|
||||
coord_t ymax;
|
||||
coord_t offsetX = 0;
|
||||
coord_t offsetY = 0;
|
||||
T * data;
|
||||
T * data_end;
|
||||
};
|
||||
|
||||
typedef BitmapBufferBase<const uint16_t> Bitmap;
|
||||
|
||||
class RLEBitmap:
|
||||
public BitmapBufferBase<uint16_t>
|
||||
{
|
||||
public:
|
||||
RLEBitmap(uint8_t format, const uint8_t* rle_data);
|
||||
~RLEBitmap();
|
||||
|
||||
static int decode(uint8_t * dest, unsigned int destSize, const uint8_t * src);
|
||||
};
|
||||
|
||||
class BitmapBuffer: public BitmapBufferBase<pixel_t>
|
||||
{
|
||||
private:
|
||||
bool dataAllocated;
|
||||
#if defined(DEBUG)
|
||||
bool leakReported;
|
||||
#endif
|
||||
lv_obj_t* canvas = nullptr;
|
||||
lv_draw_ctx_t* draw_ctx = nullptr;
|
||||
|
||||
public:
|
||||
BitmapBuffer(uint8_t format, uint16_t width, uint16_t height);
|
||||
BitmapBuffer(uint8_t format, uint16_t width, uint16_t height, uint16_t * data);
|
||||
|
||||
~BitmapBuffer();
|
||||
|
||||
void setDrawCtx(lv_draw_ctx_t* ctx) { draw_ctx = ctx; }
|
||||
void setData(uint16_t* d) {
|
||||
if (!dataAllocated) {
|
||||
data = d;
|
||||
data_end = d + (_width * _height);
|
||||
}
|
||||
}
|
||||
|
||||
inline void setFormat(uint8_t format)
|
||||
{
|
||||
this->format = format;
|
||||
}
|
||||
|
||||
inline void clear(LcdFlags flags=0)
|
||||
{
|
||||
drawSolidFilledRect(0, 0, _width - offsetX, _height - offsetY, flags);
|
||||
}
|
||||
|
||||
inline const pixel_t * getPixelPtr(coord_t x, coord_t y) const
|
||||
{
|
||||
APPLY_OFFSET();
|
||||
|
||||
coord_t w = 1, h = 1;
|
||||
if (!applyClippingRect(x, y, w, h))
|
||||
return nullptr;
|
||||
|
||||
return getPixelPtrAbs(x, y);
|
||||
}
|
||||
|
||||
inline void drawPixel(coord_t x, coord_t y, pixel_t value)
|
||||
{
|
||||
APPLY_OFFSET();
|
||||
|
||||
coord_t w = 1, h = 1;
|
||||
if (!applyClippingRect(x, y, w, h))
|
||||
return;
|
||||
|
||||
drawPixelAbs(x, y, value);
|
||||
}
|
||||
|
||||
void drawAlphaPixel(pixel_t * p, uint8_t opacity, uint16_t color);
|
||||
|
||||
inline void drawAlphaPixel(coord_t x, coord_t y, uint8_t opacity, pixel_t value)
|
||||
{
|
||||
APPLY_OFFSET();
|
||||
|
||||
coord_t w = 1, h = 1;
|
||||
if (!applyClippingRect(x, y, w, h))
|
||||
return;
|
||||
|
||||
drawAlphaPixelAbs(x, y, opacity, value);
|
||||
}
|
||||
|
||||
void drawHorizontalLine(coord_t x, coord_t y, coord_t w, uint8_t pat = SOLID, LcdFlags flags = 0, uint8_t opacity = 0);
|
||||
|
||||
void drawVerticalLine(coord_t x, coord_t y, coord_t h, uint8_t pat = SOLID, LcdFlags flags = 0, uint8_t opacity = 0);
|
||||
|
||||
void drawLine(coord_t x1, coord_t y1, coord_t x2, coord_t y2, uint8_t pat, LcdFlags att);
|
||||
|
||||
inline void drawSolidHorizontalLine(coord_t x, coord_t y, coord_t w, LcdFlags flags)
|
||||
{
|
||||
drawSolidFilledRect(x, y, w, 1, flags);
|
||||
}
|
||||
|
||||
inline void drawSolidVerticalLine(coord_t x, coord_t y, coord_t h, LcdFlags flags)
|
||||
{
|
||||
drawSolidFilledRect(x, y, 1, h, flags);
|
||||
}
|
||||
|
||||
void drawRect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t thickness = 1, uint8_t pat = SOLID, LcdFlags flags = 0, uint8_t opacity = 0);
|
||||
|
||||
inline void drawSolidRect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t thickness = 1, LcdFlags flags = 0)
|
||||
{
|
||||
drawSolidFilledRect(x, y, thickness, h, flags);
|
||||
drawSolidFilledRect(x+w-thickness, y, thickness, h, flags);
|
||||
drawSolidFilledRect(x, y, w, thickness, flags);
|
||||
drawSolidFilledRect(x, y+h-thickness, w, thickness, flags);
|
||||
}
|
||||
|
||||
void drawSolidFilledRect(coord_t x, coord_t y, coord_t w, coord_t h, LcdFlags flags = 0);
|
||||
|
||||
void drawFilledRect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t pat = SOLID, LcdFlags flags = 0, uint8_t opacity = 0);
|
||||
|
||||
void invertRect(coord_t x, coord_t y, coord_t w, coord_t h, LcdFlags flags = 0);
|
||||
|
||||
void drawFilledTriangle(coord_t x1, coord_t y1, coord_t x2, coord_t y2, coord_t x3, coord_t y3, LcdFlags flags = 0, uint8_t opacity = 0);
|
||||
|
||||
void drawCircle(coord_t x, coord_t y, coord_t radius, LcdFlags flags = 0);
|
||||
|
||||
void drawFilledCircle(coord_t x, coord_t y, coord_t radius, LcdFlags flags = 0);
|
||||
|
||||
void drawAnnulusSector(coord_t x, coord_t y, coord_t internalRadius, coord_t externalRadius, int startAngle, int endAngle, LcdFlags flags = 0);
|
||||
|
||||
void drawBitmapPie(int x0, int y0, const uint16_t * img, int startAngle, int endAngle);
|
||||
|
||||
void drawBitmapPatternPie(coord_t x0, coord_t y0, const uint8_t * img, LcdFlags flags, int startAngle, int endAngle);
|
||||
|
||||
static BitmapBuffer * loadBitmap(const char * filename, BitmapFormats fmt = BMP_INVALID);
|
||||
static BitmapBuffer * loadRamBitmap(const uint8_t * buffer, int len);
|
||||
|
||||
static BitmapBuffer * loadMask(const char * filename);
|
||||
static BitmapBuffer * load8bitMask(const uint8_t * lbm);
|
||||
static BitmapBuffer * load8bitMaskLZ4(const uint8_t * compressed_data);
|
||||
|
||||
static BitmapBuffer * loadMaskOnBackground(const char * filename, LcdFlags foreground, LcdFlags background);
|
||||
static BitmapBuffer * load8bitMaskOnBackground(const uint8_t * lbm, LcdFlags foreground, LcdFlags background);
|
||||
|
||||
static uint8_t * loadFont(const uint8_t * lbm, int len, int& w, int& h);
|
||||
|
||||
uint8_t * to8bitMask(size_t* size) const;
|
||||
|
||||
void drawMask(coord_t x, coord_t y, const BitmapBuffer * mask, LcdFlags flags, coord_t offsetX = 0, coord_t width = 0);
|
||||
|
||||
void drawMask(coord_t x, coord_t y, const BitmapBuffer * mask, const BitmapBuffer * srcBitmap, coord_t offsetX = 0, coord_t offsetY = 0, coord_t width = 0, coord_t height = 0);
|
||||
|
||||
void drawBitmapPattern(coord_t x, coord_t y, const uint8_t * bmp, LcdFlags flags, coord_t offset=0, coord_t width=0);
|
||||
|
||||
coord_t drawSizedText(coord_t x, coord_t y, const char * s, uint8_t len, LcdFlags flags=0);
|
||||
|
||||
coord_t drawText(coord_t x, coord_t y, const char * s, LcdFlags flags = 0)
|
||||
{
|
||||
if (!s) return x;
|
||||
return drawSizedText(x, y, s, strlen(s), flags);
|
||||
}
|
||||
|
||||
coord_t drawTextAtIndex(coord_t x, coord_t y, const char *const *s, uint8_t idx, LcdFlags flags = 0)
|
||||
{
|
||||
return drawText(x, y, s[idx], flags);
|
||||
}
|
||||
|
||||
static void formatNumberAsString(char *buffer, const uint8_t buffer_size, int32_t val, LcdFlags flags = 0, uint8_t len = 0, const char * prefix = nullptr, const char * suffix = nullptr);
|
||||
|
||||
coord_t drawNumber(coord_t x, coord_t y, int32_t val, LcdFlags flags = 0, uint8_t len = 0, const char * prefix = nullptr, const char * suffix = nullptr);
|
||||
|
||||
template<class T>
|
||||
void drawBitmap(coord_t x, coord_t y, const T * bmp, coord_t srcx = 0, coord_t srcy = 0, coord_t srcw = 0, coord_t srch = 0, float scale = 0);
|
||||
|
||||
template<class T>
|
||||
void drawScaledBitmap(const T * bitmap, coord_t x, coord_t y, coord_t w, coord_t h);
|
||||
|
||||
BitmapBuffer * horizontalFlip() const;
|
||||
|
||||
BitmapBuffer * verticalFlip() const;
|
||||
|
||||
BitmapBuffer * invertMask() const;
|
||||
|
||||
protected:
|
||||
static BitmapBuffer * load_bmp(const char * filename);
|
||||
static BitmapBuffer * load_stb(const char * filename, BitmapFormats fmt = BMP_INVALID);
|
||||
static BitmapBuffer * load_stb_buffer(const uint8_t * buffer, int len);
|
||||
static BitmapBuffer * convert_stb_bitmap(uint8_t * img, int w, int h, int n,
|
||||
BitmapFormats fmt = BMP_INVALID);
|
||||
|
||||
inline bool applyClippingRect(coord_t & x, coord_t & y, coord_t & w, coord_t & h) const
|
||||
{
|
||||
if (h < 0) {
|
||||
y += h;
|
||||
h = -h;
|
||||
}
|
||||
|
||||
if (w < 0) {
|
||||
x += w;
|
||||
w = -w;
|
||||
}
|
||||
|
||||
if (x >= xmax || y >= ymax)
|
||||
return false;
|
||||
|
||||
if (y < ymin) {
|
||||
h += y - ymin;
|
||||
y = ymin;
|
||||
}
|
||||
|
||||
if (x < xmin) {
|
||||
w += x - xmin;
|
||||
x = xmin;
|
||||
}
|
||||
|
||||
if (y + h > ymax)
|
||||
h = ymax - y;
|
||||
|
||||
if (x + w > xmax)
|
||||
w = xmax - x;
|
||||
|
||||
return data && h > 0 && w > 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void drawBitmapAbs(coord_t x, coord_t y, const T* bmp, coord_t srcx = 0,
|
||||
coord_t srcy = 0, coord_t srcw = 0, coord_t srch = 0,
|
||||
float scale = 0);
|
||||
|
||||
inline void drawPixel(pixel_t * p, pixel_t value)
|
||||
{
|
||||
if (data && (data <= p && p < data_end)) {
|
||||
*p = value;
|
||||
}
|
||||
#if defined(DEBUG)
|
||||
else if (!leakReported) {
|
||||
leakReported = true;
|
||||
TRACE("BitmapBuffer(%p).drawPixel(): buffer overrun, data: %p, written at: %p", this, data, p);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
inline const pixel_t * getPixelPtrAbs(coord_t x, coord_t y) const
|
||||
{
|
||||
#if defined(LCD_VERTICAL_INVERT) && 0
|
||||
x = _width - x - 1;
|
||||
y = _height - y - 1;
|
||||
#endif
|
||||
return &data[y * _width + x];
|
||||
}
|
||||
|
||||
inline pixel_t * getPixelPtrAbs(coord_t x, coord_t y)
|
||||
{
|
||||
#if defined(LCD_VERTICAL_INVERT) && 0
|
||||
x = _width - x - 1;
|
||||
y = _height - y - 1;
|
||||
#endif
|
||||
return &data[y * _width + x];
|
||||
}
|
||||
|
||||
inline void drawPixelAbs(coord_t x, coord_t y, pixel_t value)
|
||||
{
|
||||
pixel_t * p = getPixelPtrAbs(x, y);
|
||||
drawPixel(p, value);
|
||||
}
|
||||
|
||||
inline void drawAlphaPixelAbs(coord_t x, coord_t y, uint8_t opacity, uint16_t color)
|
||||
{
|
||||
pixel_t * p = getPixelPtrAbs(x, y);
|
||||
drawAlphaPixel(p, opacity, color);
|
||||
}
|
||||
|
||||
void drawHorizontalLineAbs(coord_t x, coord_t y, coord_t w, uint8_t pat, LcdFlags flags, uint8_t opacity);
|
||||
|
||||
bool liangBarskyClipper(coord_t& x1, coord_t& y1, coord_t& x2, coord_t& y2);
|
||||
};
|
||||
|
||||
class LZ4Bitmap : public BitmapBuffer
|
||||
{
|
||||
public:
|
||||
LZ4Bitmap(uint8_t format, const uint8_t* compressed_data);
|
||||
~LZ4Bitmap();
|
||||
};
|
||||
|
||||
class LZ4Mask : public BitmapBufferBase<uint8_t>
|
||||
{
|
||||
public:
|
||||
LZ4Mask(const uint8_t* compressed_data);
|
||||
~LZ4Mask();
|
||||
};
|
||||
|
||||
// Back buffer to draw
|
||||
extern BitmapBuffer * lcd;
|
||||
|
||||
// Buffer currently on display
|
||||
extern BitmapBuffer * lcdFront;
|
||||
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "window.h"
|
||||
|
||||
template <class T>
|
||||
class BufferedWindow: public T
|
||||
{
|
||||
public:
|
||||
using T::T;
|
||||
|
||||
~BufferedWindow() override
|
||||
{
|
||||
delete bitmap;
|
||||
}
|
||||
|
||||
void invalidate(const rect_t & rect) override
|
||||
{
|
||||
paintUpdateNeeded = true;
|
||||
T::invalidate(rect);
|
||||
}
|
||||
|
||||
protected:
|
||||
BitmapBuffer * bitmap = nullptr;
|
||||
bool paintUpdateNeeded = false;
|
||||
virtual void paintUpdate(BitmapBuffer * dc) = 0;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class OpaqueBufferedWindow: public BufferedWindow<T>
|
||||
{
|
||||
public:
|
||||
using BufferedWindow<T>::BufferedWindow;
|
||||
|
||||
void paint(BitmapBuffer * dc) override
|
||||
{
|
||||
if (!this->bitmap) {
|
||||
this->bitmap = new BitmapBuffer(BMP_RGB565, T::width(), T::height());
|
||||
this->paintUpdateNeeded = true;
|
||||
}
|
||||
|
||||
if (this->paintUpdateNeeded) {
|
||||
this->paintUpdate(this->bitmap);
|
||||
this->paintUpdateNeeded = false;
|
||||
}
|
||||
|
||||
dc->drawBitmap(0, 0, this->bitmap);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class TransparentBufferedWindow: public BufferedWindow<T>
|
||||
{
|
||||
public:
|
||||
using BufferedWindow<T>::BufferedWindow;
|
||||
|
||||
void paint(BitmapBuffer * dc) override
|
||||
{
|
||||
if (!BufferedWindow<T>::bitmap) {
|
||||
this->bitmap = new BitmapBuffer(BMP_RGB565, T::width(), T::height());
|
||||
this->paintUpdateNeeded = true;
|
||||
}
|
||||
|
||||
if (this->paintUpdateNeeded) {
|
||||
this->paintUpdate(dc);
|
||||
// we can only store the bitmap if fully drawn
|
||||
coord_t xmin, xmax, ymin, ymax;
|
||||
dc->getClippingRect(xmin, xmax, ymin, ymax);
|
||||
if (xmax - xmin >= this->width() && ymax - ymin >= this->height()) {
|
||||
this->bitmap->drawBitmap(0, 0, dc, dc->getOffsetX(), dc->getOffsetY());
|
||||
this->paintUpdateNeeded = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dc->drawBitmap(0, 0, this->bitmap);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class TransparentBitmapBackground: public TransparentBufferedWindow<Window>
|
||||
{
|
||||
public:
|
||||
TransparentBitmapBackground(Window * parent, const rect_t & rect, const BitmapBuffer * bitmap):
|
||||
TransparentBufferedWindow<Window>(parent, rect, OPAQUE),
|
||||
background(bitmap)
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "TransparentBitmapBackground";
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
const BitmapBuffer * background;
|
||||
|
||||
void paintUpdate(BitmapBuffer * dc) override
|
||||
{
|
||||
if (background) {
|
||||
dc->drawBitmap((width() - background->width()) / 2, (height() - background->height()) / 2, background);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "libopenui_config.h"
|
||||
#include "button.h"
|
||||
#include "font.h"
|
||||
#include "theme.h"
|
||||
|
||||
#include "widgets/simple_btn.h"
|
||||
|
||||
static void update_checked_flag(lv_obj_t* obj, WindowFlags flags)
|
||||
{
|
||||
if (!(flags & BUTTON_CHECKED))
|
||||
lv_obj_clear_state(obj, LV_STATE_CHECKED);
|
||||
else
|
||||
lv_obj_add_state(obj, LV_STATE_CHECKED);
|
||||
}
|
||||
|
||||
Button::Button(Window* parent, const rect_t& rect,
|
||||
std::function<uint8_t(void)> pressHandler,
|
||||
WindowFlags windowFlag, LcdFlags textFlags,
|
||||
LvglCreate objConstruct) :
|
||||
FormField(parent, rect, windowFlag, textFlags,
|
||||
objConstruct ? objConstruct : simple_btn_create),
|
||||
pressHandler(std::move(pressHandler))
|
||||
{
|
||||
lv_obj_add_event_cb(lvobj, Button::long_pressed, LV_EVENT_LONG_PRESSED, nullptr);
|
||||
update_checked_flag(lvobj, windowFlags);
|
||||
}
|
||||
|
||||
void Button::check(bool checked)
|
||||
{
|
||||
if (_deleted) return;
|
||||
if (checked != bool(windowFlags & BUTTON_CHECKED)) {
|
||||
windowFlags ^= BUTTON_CHECKED;
|
||||
update_checked_flag(lvobj, windowFlags);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
bool Button::checked() const
|
||||
{
|
||||
if (windowFlags & BUTTON_CHECKED_ON_FOCUS)
|
||||
return hasFocus();
|
||||
else
|
||||
return windowFlags & BUTTON_CHECKED;
|
||||
}
|
||||
|
||||
void Button::onPress()
|
||||
{
|
||||
check(pressHandler && pressHandler());
|
||||
}
|
||||
|
||||
void Button::onLongPress()
|
||||
{
|
||||
if (longPressHandler) {
|
||||
check(longPressHandler());
|
||||
lv_obj_clear_state(lvobj, LV_STATE_PRESSED);
|
||||
lv_indev_wait_release(lv_indev_get_act());
|
||||
}
|
||||
}
|
||||
|
||||
void Button::onClicked()
|
||||
{
|
||||
onPress();
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
// this needs to stay so that viewmain doesnt get the touch event
|
||||
bool Button::onTouchEnd(coord_t x, coord_t y) { return true; }
|
||||
#endif
|
||||
|
||||
void Button::checkEvents()
|
||||
{
|
||||
Window::checkEvents();
|
||||
if (checkHandler) checkHandler();
|
||||
}
|
||||
|
||||
void Button::long_pressed(lv_event_t* e)
|
||||
{
|
||||
auto obj = lv_event_get_target(e);
|
||||
auto btn = (Button*)lv_obj_get_user_data(obj);
|
||||
if (obj) btn->onLongPress();
|
||||
}
|
||||
|
||||
|
||||
TextButton::TextButton(Window* parent, const rect_t& rect, std::string text,
|
||||
std::function<uint8_t(void)> pressHandler,
|
||||
WindowFlags windowFlags) :
|
||||
Button(parent, rect, std::move(pressHandler), windowFlags, 0, lv_btn_create),
|
||||
text(std::move(text))
|
||||
{
|
||||
update_checked_flag(lvobj, windowFlags);
|
||||
|
||||
label = lv_label_create(lvobj);
|
||||
lv_label_set_text(label, this->text.c_str());
|
||||
lv_obj_center(label);
|
||||
}
|
||||
|
||||
void IconButton::paint(BitmapBuffer * dc)
|
||||
{
|
||||
dc->drawBitmap(0, 0, theme->getIcon(icon, checked() ? STATE_PRESSED : STATE_DEFAULT));
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "form.h"
|
||||
|
||||
constexpr WindowFlags BUTTON_BACKGROUND = FORM_FLAGS_LAST << 1u;
|
||||
constexpr WindowFlags BUTTON_CHECKED = FORM_FLAGS_LAST << 2u;
|
||||
constexpr WindowFlags BUTTON_CHECKED_ON_FOCUS = FORM_FLAGS_LAST << 3u;
|
||||
|
||||
class Button : public FormField
|
||||
{
|
||||
public:
|
||||
Button(Window* parent, const rect_t& rect,
|
||||
std::function<uint8_t(void)> pressHandler = nullptr,
|
||||
WindowFlags windowFlags = 0, LcdFlags textFlags = 0,
|
||||
LvglCreate objConstruct = nullptr);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override { return "Button"; }
|
||||
#endif
|
||||
|
||||
virtual void onPress();
|
||||
virtual void onLongPress();
|
||||
|
||||
void onClicked() override;
|
||||
void checkEvents() override;
|
||||
|
||||
void check(bool checked = true);
|
||||
bool checked() const;
|
||||
|
||||
void setPressHandler(std::function<uint8_t(void)> handler)
|
||||
{
|
||||
pressHandler = std::move(handler);
|
||||
}
|
||||
|
||||
void setLongPressHandler(std::function<uint8_t(void)> handler)
|
||||
{
|
||||
longPressHandler = std::move(handler);
|
||||
}
|
||||
|
||||
void setCheckHandler(std::function<void(void)> handler)
|
||||
{
|
||||
checkHandler = std::move(handler);
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool onTouchEnd(coord_t x, coord_t y) override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
std::function<uint8_t(void)> pressHandler;
|
||||
std::function<uint8_t(void)> longPressHandler;
|
||||
std::function<void(void)> checkHandler;
|
||||
|
||||
static void long_pressed(lv_event_t* e);
|
||||
};
|
||||
|
||||
class TextButton: public Button
|
||||
{
|
||||
public:
|
||||
TextButton(Window* parent, const rect_t& rect, std::string text,
|
||||
std::function<uint8_t(void)> pressHandler = nullptr,
|
||||
WindowFlags windowFlags = BUTTON_BACKGROUND | OPAQUE);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "TextButton \"" + text + "\"";
|
||||
}
|
||||
#endif
|
||||
|
||||
void setText(std::string value)
|
||||
{
|
||||
if (value != text) {
|
||||
text = std::move(value);
|
||||
lv_label_set_text(label, text.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void setBgColorHandler(std::function<LcdFlags(void)> handler = nullptr)
|
||||
{
|
||||
bgColorHandler = std::move(handler);
|
||||
}
|
||||
|
||||
protected:
|
||||
lv_obj_t * label = nullptr;
|
||||
|
||||
std::string text;
|
||||
std::function<LcdFlags(void)> bgColorHandler = nullptr;
|
||||
};
|
||||
|
||||
class IconButton: public Button
|
||||
{
|
||||
public:
|
||||
IconButton(Window* parent, const rect_t& rect, uint8_t icon,
|
||||
std::function<uint8_t(void)> pressHandler,
|
||||
WindowFlags flags = 0) :
|
||||
Button(parent, rect, std::move(pressHandler), flags), icon(icon)
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "IconButton(" + std::to_string(icon) + ")";
|
||||
}
|
||||
#endif
|
||||
|
||||
void paint(BitmapBuffer * dc) override;
|
||||
|
||||
protected:
|
||||
uint8_t icon;
|
||||
};
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/EdgeTX/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "button_matrix.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char _filler[] = "0";
|
||||
static const char _newline[] = "\n";
|
||||
static const char _map_end[] = "";
|
||||
|
||||
static void btn_matrix_event(lv_event_t *e)
|
||||
{
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
|
||||
if (code == LV_EVENT_VALUE_CHANGED) {
|
||||
lv_obj_t* obj = lv_event_get_target(e);
|
||||
auto btn_id = (uint32_t *)lv_event_get_param(e);
|
||||
auto btnm = (ButtonMatrix*)lv_event_get_user_data(e);
|
||||
|
||||
bool edited = lv_obj_has_state(obj, LV_STATE_EDITED);
|
||||
bool is_pointer = lv_indev_get_type(lv_indev_get_act()) == LV_INDEV_TYPE_POINTER;
|
||||
if (edited || is_pointer)
|
||||
btnm->onPress((uint8_t)*btn_id);
|
||||
}
|
||||
else if (code == LV_EVENT_DRAW_PART_BEGIN) {
|
||||
|
||||
lv_obj_draw_part_dsc_t* dsc = lv_event_get_draw_part_dsc(e);
|
||||
if (dsc->part == LV_PART_ITEMS) {
|
||||
auto btnm = (ButtonMatrix*)lv_event_get_user_data(e);
|
||||
if (btnm->isActive((uint8_t)dsc->id)) {
|
||||
dsc->rect_dsc->bg_color = makeLvColor(COLOR_THEME_ACTIVE);
|
||||
dsc->label_dsc->color = makeLvColor(COLOR_THEME_PRIMARY2);
|
||||
} else {
|
||||
dsc->rect_dsc->bg_color = makeLvColor(COLOR_THEME_PRIMARY2);
|
||||
dsc->label_dsc->color = makeLvColor(COLOR_THEME_SECONDARY1);
|
||||
}
|
||||
} else if (dsc->part == LV_PART_MAIN) {
|
||||
lv_obj_t* obj = lv_event_get_target(e);
|
||||
if (lv_obj_has_state(obj, LV_STATE_FOCUS_KEY) &&
|
||||
!lv_obj_has_state(obj, LV_STATE_EDITED)) {
|
||||
dsc->rect_dsc->bg_color = makeLvColor(COLOR_THEME_FOCUS);
|
||||
dsc->rect_dsc->bg_opa = LV_OPA_20;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ButtonMatrix::ButtonMatrix(Window* parent, const rect_t& r) :
|
||||
FormField(parent, r, 0, 0, lv_btnmatrix_create)
|
||||
{
|
||||
lv_obj_add_flag(lvobj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
|
||||
lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICK_FOCUSABLE);
|
||||
|
||||
lv_obj_add_event_cb(lvobj, btn_matrix_event, LV_EVENT_ALL, this);
|
||||
}
|
||||
|
||||
ButtonMatrix::~ButtonMatrix()
|
||||
{
|
||||
deallocate();
|
||||
}
|
||||
|
||||
void ButtonMatrix::deallocate()
|
||||
{
|
||||
if (txt_cnt == 0) return;
|
||||
|
||||
for (uint8_t i = 0; i < txt_cnt; i++) {
|
||||
char* txt = lv_btnm_map[i];
|
||||
if (txt != _filler && txt != _newline && txt != _map_end) free(txt);
|
||||
}
|
||||
|
||||
free(lv_btnm_map);
|
||||
free(txt_index);
|
||||
|
||||
txt_cnt = 0;
|
||||
btn_cnt = 0;
|
||||
}
|
||||
|
||||
void ButtonMatrix::initBtnMap(uint8_t cols, uint8_t btns)
|
||||
{
|
||||
deallocate();
|
||||
|
||||
uint8_t rows = ((btns - 1) / cols) + 1;
|
||||
txt_cnt = btns + rows;
|
||||
btn_cnt = btns;
|
||||
|
||||
lv_btnm_map = (char**)malloc(sizeof(char*) * txt_cnt);
|
||||
txt_index = (uint8_t*)malloc(sizeof(uint8_t) * btns);
|
||||
|
||||
uint8_t col = 0;
|
||||
uint8_t btn = 0;
|
||||
uint8_t txt_i = 0;
|
||||
|
||||
while (btn < btns) {
|
||||
|
||||
if (col == cols) {
|
||||
lv_btnm_map[txt_i++] = (char*)_newline;
|
||||
col = 0;
|
||||
}
|
||||
|
||||
txt_index[btn] = txt_i;
|
||||
lv_btnm_map[txt_i++] = (char*)_filler;
|
||||
btn++;
|
||||
col++;
|
||||
}
|
||||
lv_btnm_map[txt_i++] = (char*)_map_end;
|
||||
}
|
||||
|
||||
void ButtonMatrix::setText(uint8_t btn_id, const char* txt)
|
||||
{
|
||||
if (btn_id >= btn_cnt) return;
|
||||
|
||||
uint8_t txt_i = txt_index[btn_id];
|
||||
lv_btnm_map[txt_i] = strdup(txt);
|
||||
}
|
||||
|
||||
void ButtonMatrix::update()
|
||||
{
|
||||
lv_btnmatrix_set_map(lvobj, (const char**)lv_btnm_map);
|
||||
|
||||
lv_btnmatrix_ctrl_t ctrl = LV_BTNMATRIX_CTRL_CLICK_TRIG |
|
||||
LV_BTNMATRIX_CTRL_NO_REPEAT;
|
||||
|
||||
lv_btnmatrix_set_btn_ctrl_all(lvobj, ctrl);
|
||||
}
|
||||
|
||||
void ButtonMatrix::onClicked()
|
||||
{
|
||||
lv_group_focus_obj(lvobj);
|
||||
FormField::onClicked();
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/EdgeTX/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "form.h"
|
||||
|
||||
class ButtonMatrix : public FormField
|
||||
{
|
||||
char** lv_btnm_map = nullptr;
|
||||
uint8_t* txt_index = nullptr;
|
||||
uint8_t txt_cnt = 0;
|
||||
uint8_t btn_cnt = 0;
|
||||
|
||||
public:
|
||||
ButtonMatrix(Window* parent, const rect_t& rect);
|
||||
~ButtonMatrix();
|
||||
|
||||
virtual void onPress(uint8_t btn_id) {}
|
||||
virtual bool isActive(uint8_t btn_id) { return false; }
|
||||
|
||||
protected:
|
||||
void deallocate();
|
||||
void initBtnMap(uint8_t cols, uint8_t btns);
|
||||
void setText(uint8_t btn_id, const char* txt);
|
||||
void update();
|
||||
|
||||
void onClicked() override;
|
||||
};
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "carousel.h"
|
||||
|
||||
void CarouselWindow::update()
|
||||
{
|
||||
auto first = min<int>(selection - 2, items.size() - count);
|
||||
first = max(0, first);
|
||||
coord_t lastPosition = 0;
|
||||
coord_t spacing = 10;
|
||||
if (!items.empty() && count > 0)
|
||||
spacing = (width() - items[0]->back->width() * (count - 1) - items[0]->front->width()) / (count - 1);
|
||||
|
||||
int index = 0;
|
||||
for (auto & item: items) {
|
||||
Window * window;
|
||||
if (index == selection) {
|
||||
item->back->detach();
|
||||
window = item->front;
|
||||
}
|
||||
else {
|
||||
item->front->detach();
|
||||
window = item->back;
|
||||
}
|
||||
window->attach(this);
|
||||
window->setLeft(lastPosition);
|
||||
window->setTop((height() - window->height()) / 2);
|
||||
lastPosition += window->width() + spacing;
|
||||
index += 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void Carousel::onEvent(event_t event)
|
||||
{
|
||||
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
|
||||
|
||||
if (event == EVT_ROTARY_RIGHT) {
|
||||
if (body->selection < (int)body->items.size() - 1)
|
||||
select(body->selection + 1);
|
||||
}
|
||||
else if (event == EVT_ROTARY_LEFT) {
|
||||
if (body->selection > 0)
|
||||
select(body->selection - 1);
|
||||
}
|
||||
else {
|
||||
Window::onEvent(event);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "button.h"
|
||||
|
||||
class CarouselItem
|
||||
{
|
||||
public:
|
||||
CarouselItem(Window * front, Window * back):
|
||||
front(front),
|
||||
back(back)
|
||||
{
|
||||
}
|
||||
|
||||
void setSelectHandler(std::function<void()> handler)
|
||||
{
|
||||
selectHandler = std::move(handler);
|
||||
}
|
||||
|
||||
virtual ~CarouselItem() = default;
|
||||
|
||||
public:
|
||||
Window * front;
|
||||
Window * back;
|
||||
std::function<void()> selectHandler;
|
||||
};
|
||||
|
||||
class CarouselWindow: public Window
|
||||
{
|
||||
friend class Carousel;
|
||||
|
||||
public:
|
||||
CarouselWindow(Window * parent, const rect_t & rect, uint8_t count):
|
||||
Window(parent, rect, NO_SCROLLBAR),
|
||||
count(count)
|
||||
{
|
||||
}
|
||||
|
||||
void deleteLater(bool detach = true, bool trash = true) override // NOLINT(google-default-arguments)
|
||||
{
|
||||
if (_deleted)
|
||||
return;
|
||||
|
||||
clear();
|
||||
Window::deleteLater(detach, trash);
|
||||
}
|
||||
|
||||
void addItem(CarouselItem * item)
|
||||
{
|
||||
items.push_back(item);
|
||||
update();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
// children will be deleted later (front and back)
|
||||
children.clear();
|
||||
|
||||
for (auto & item: items) {
|
||||
item->front->deleteLater();
|
||||
item->back->deleteLater();
|
||||
delete item;
|
||||
}
|
||||
items.clear();
|
||||
}
|
||||
|
||||
void select(int index, bool scroll = true)
|
||||
{
|
||||
selection = index;
|
||||
if (selection >= 0) {
|
||||
auto item = items[selection];
|
||||
if (item->selectHandler) {
|
||||
item->selectHandler();
|
||||
}
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::vector<CarouselItem *> items;
|
||||
int selection = 0;
|
||||
unsigned count;
|
||||
void update();
|
||||
};
|
||||
|
||||
class Carousel: public Window
|
||||
{
|
||||
public:
|
||||
Carousel(Window * parent, const rect_t & rect):
|
||||
Window(parent, rect, NO_SCROLLBAR)
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "Carousel";
|
||||
}
|
||||
#endif
|
||||
|
||||
void addItem(CarouselItem * item)
|
||||
{
|
||||
body->addItem(item);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
body->clear();
|
||||
}
|
||||
|
||||
void select(int index)
|
||||
{
|
||||
body->select(index);
|
||||
previousButton->enable(index > 0);
|
||||
nextButton->enable(index < (int)body->items.size() - 1);
|
||||
}
|
||||
|
||||
int getSelection() const
|
||||
{
|
||||
return body->selection;
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void onEvent(event_t event) override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
Button * previousButton = nullptr;
|
||||
Button * nextButton = nullptr;
|
||||
CarouselWindow * body = nullptr;
|
||||
};
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "checkbox.h"
|
||||
#include "theme.h"
|
||||
|
||||
|
||||
static void checkbox_event_handler(lv_event_t* e)
|
||||
{
|
||||
lv_obj_t* target = lv_event_get_target(e);
|
||||
CheckBox* cb = (CheckBox*)lv_obj_get_user_data(target);
|
||||
|
||||
if (cb) cb->setValue(lv_obj_get_state(target) & LV_STATE_CHECKED);
|
||||
}
|
||||
|
||||
CheckBox::CheckBox(Window* parent, const rect_t& rect,
|
||||
std::function<uint8_t()> getValue,
|
||||
std::function<void(uint8_t)> setValue, WindowFlags flags) :
|
||||
FormField(parent, rect, flags, 0, lv_switch_create),
|
||||
_getValue(std::move(getValue)),
|
||||
_setValue(std::move(setValue))
|
||||
{
|
||||
// TODO: migrate to default theme
|
||||
|
||||
if (height() > 0)
|
||||
lv_obj_set_width(lvobj, (lv_coord_t)(height() * 1.7f));
|
||||
|
||||
// PART_MAIN
|
||||
lv_obj_set_style_bg_color(lvobj, makeLvColor(COLOR_THEME_DISABLED), LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(lvobj, makeLvColor(COLOR_THEME_DISABLED), LV_STATE_FOCUSED);
|
||||
|
||||
update();
|
||||
|
||||
lv_obj_add_event_cb(lvobj, checkbox_event_handler,
|
||||
LV_EVENT_VALUE_CHANGED, this);
|
||||
}
|
||||
|
||||
void CheckBox::update() const
|
||||
{
|
||||
if (!_getValue) return;
|
||||
if (_getValue()) lv_obj_add_state(lvobj, LV_STATE_CHECKED);
|
||||
else lv_obj_clear_state(lvobj, LV_STATE_CHECKED);
|
||||
}
|
||||
|
||||
void CheckBox::onClicked()
|
||||
{
|
||||
// prevent FormField::onClicked()
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include "form.h"
|
||||
|
||||
class CheckBox : public FormField
|
||||
{
|
||||
public:
|
||||
CheckBox(Window* parent, const rect_t& rect,
|
||||
std::function<uint8_t()> getValue,
|
||||
std::function<void(uint8_t)> setValue, WindowFlags flags = 0);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override { return "CheckBox"; }
|
||||
#endif
|
||||
|
||||
void onClicked() override;
|
||||
|
||||
const char* getLabel() const { return label.c_str(); }
|
||||
void setLabel(std::string newLabel) { label = std::move(newLabel); }
|
||||
|
||||
uint8_t getValue() const { return _getValue(); }
|
||||
void setValue(uint8_t value) { _setValue(value); }
|
||||
|
||||
void setSetValueHandler(std::function<void(uint8_t)> handler)
|
||||
{
|
||||
_setValue = std::move(handler);
|
||||
}
|
||||
|
||||
void setGetValueHandler(std::function<uint8_t()> handler)
|
||||
{
|
||||
_getValue = std::move(handler);
|
||||
}
|
||||
|
||||
void update() const;
|
||||
|
||||
protected:
|
||||
std::string label;
|
||||
std::function<uint8_t()> _getValue;
|
||||
std::function<void(uint8_t)> _setValue;
|
||||
};
|
||||
+245
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "choice.h"
|
||||
#include "menu.h"
|
||||
#include "theme.h"
|
||||
|
||||
void choice_changed_cb(lv_event_t *e)
|
||||
{
|
||||
auto code = lv_event_get_code(e);
|
||||
|
||||
if (code == LV_EVENT_VALUE_CHANGED) {
|
||||
lv_obj_t *target = lv_event_get_target(e);
|
||||
if (target != nullptr) {
|
||||
ChoiceBase *cb = (ChoiceBase*)lv_obj_get_user_data(target);
|
||||
if (cb) {
|
||||
std::string text = cb->getLabelText();
|
||||
lv_label_set_text(cb->label, text.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ChoiceBase::ChoiceBase(Window* parent, const rect_t& rect, ChoiceType type,
|
||||
WindowFlags windowFlags) :
|
||||
FormField(parent, rect, windowFlags), type(type)
|
||||
{
|
||||
lv_obj_set_height(lvobj, LV_SIZE_CONTENT);
|
||||
lv_obj_set_width(lvobj, LV_SIZE_CONTENT);
|
||||
lv_obj_set_layout(lvobj, LV_LAYOUT_FLEX);
|
||||
lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_ROW);
|
||||
|
||||
if (height() == 0)
|
||||
{
|
||||
lv_obj_set_style_pad_top(lvobj, 4, LV_PART_MAIN);
|
||||
lv_obj_set_style_pad_bottom(lvobj, 4, LV_PART_MAIN);
|
||||
lv_obj_set_style_radius(lvobj, 4, LV_PART_MAIN);
|
||||
}
|
||||
|
||||
lv_obj_add_event_cb(lvobj, choice_changed_cb, LV_EVENT_VALUE_CHANGED, lvobj);
|
||||
label = lv_label_create(lvobj);
|
||||
|
||||
lv_group_t * def_group = lv_group_get_default();
|
||||
if(def_group) {
|
||||
lv_group_add_obj(def_group, lvobj);
|
||||
}
|
||||
|
||||
// Normal font and background color
|
||||
lv_obj_set_style_bg_color(lvobj, makeLvColor(COLOR_THEME_PRIMARY2), LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_opa(lvobj, LV_OPA_100, LV_PART_MAIN);
|
||||
lv_obj_set_style_pad_right(lvobj, 5, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_width(lvobj, 1, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_color(lvobj, makeLvColor(COLOR_THEME_SECONDARY2), LV_PART_MAIN);
|
||||
lv_obj_set_style_text_color(lvobj, makeLvColor(COLOR_THEME_SECONDARY1), LV_PART_MAIN);
|
||||
|
||||
// focused
|
||||
lv_obj_set_style_bg_color(lvobj, makeLvColor(COLOR_THEME_FOCUS), LV_PART_MAIN | LV_STATE_FOCUSED);
|
||||
lv_obj_set_style_text_color(lvobj, makeLvColor(COLOR_THEME_PRIMARY2), LV_PART_MAIN | LV_STATE_FOCUSED);
|
||||
|
||||
lv_obj_set_style_pad_left(label, FIELD_PADDING_LEFT, LV_PART_MAIN);
|
||||
lv_obj_set_style_pad_top(label, FIELD_PADDING_TOP, LV_PART_MAIN);
|
||||
lv_obj_set_style_pad_right(label, CHOICE_LABEL_MARGIN_RIGHT, LV_PART_MAIN);
|
||||
// lv_obj_set
|
||||
|
||||
// add the image
|
||||
lv_obj_t *img = lv_img_create(lvobj);
|
||||
lv_img_set_src(img, type == CHOICE_TYPE_DROPOWN ? LV_SYMBOL_DOWN : LV_SYMBOL_DIRECTORY);
|
||||
lv_obj_set_align(img, LV_ALIGN_RIGHT_MID);
|
||||
}
|
||||
|
||||
std::string Choice::getLabelText()
|
||||
{
|
||||
std::string text;
|
||||
|
||||
if (textHandler != nullptr) {
|
||||
if (_getValue) { text = textHandler(_getValue()); }
|
||||
} else if (_getValue) {
|
||||
int val = _getValue();
|
||||
val -= vmin;
|
||||
if (val >= 0 && val < (int)values.size()) {
|
||||
text = values[val];
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
Choice::Choice(Window* parent, const rect_t& rect, int vmin, int vmax,
|
||||
std::function<int()> _getValue,
|
||||
std::function<void(int)> _setValue, WindowFlags windowFlags) :
|
||||
ChoiceBase(parent, rect, CHOICE_TYPE_DROPOWN, windowFlags),
|
||||
vmin(vmin),
|
||||
vmax(vmax),
|
||||
_getValue(std::move(_getValue)),
|
||||
_setValue(std::move(_setValue))
|
||||
{
|
||||
lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
}
|
||||
|
||||
Choice::Choice(Window* parent, const rect_t& rect, const char* const values[],
|
||||
int vmin, int vmax, std::function<int()> _getValue,
|
||||
std::function<void(int)> _setValue, WindowFlags windowFlags) :
|
||||
ChoiceBase(parent, rect, CHOICE_TYPE_DROPOWN, windowFlags),
|
||||
vmin(vmin),
|
||||
vmax(vmax),
|
||||
_getValue(std::move(_getValue)),
|
||||
_setValue(std::move(_setValue))
|
||||
{
|
||||
setValues(values);
|
||||
lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
}
|
||||
|
||||
Choice::Choice(Window* parent, const rect_t& rect,
|
||||
std::vector<std::string> values, int vmin, int vmax,
|
||||
std::function<int()> _getValue, std::function<void(int)> _setValue,
|
||||
WindowFlags windowFlags) :
|
||||
ChoiceBase(parent, rect, CHOICE_TYPE_DROPOWN, windowFlags),
|
||||
values(std::move(values)),
|
||||
vmin(vmin),
|
||||
vmax(vmax),
|
||||
_getValue(std::move(_getValue)),
|
||||
_setValue(std::move(_setValue))
|
||||
{
|
||||
lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
}
|
||||
|
||||
Choice::Choice(Window* parent, const rect_t& rect, const char* values, int vmin,
|
||||
int vmax, std::function<int()> _getValue,
|
||||
std::function<void(int)> _setValue, WindowFlags windowFlags) :
|
||||
ChoiceBase(parent, rect, CHOICE_TYPE_DROPOWN, windowFlags),
|
||||
vmin(vmin),
|
||||
vmax(vmax),
|
||||
_getValue(std::move(_getValue)),
|
||||
_setValue(std::move(_setValue))
|
||||
{
|
||||
if (values) {
|
||||
uint8_t len = values[0];
|
||||
const char* value = &values[1];
|
||||
for (int i = vmin; i <= vmax; i++) {
|
||||
this->values.emplace_back(
|
||||
std::string(value, min<uint8_t>(len, strlen(value))));
|
||||
value += len;
|
||||
}
|
||||
}
|
||||
lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
}
|
||||
|
||||
void Choice::addValue(const char * value)
|
||||
{
|
||||
values.emplace_back(value);
|
||||
vmax += 1;
|
||||
}
|
||||
|
||||
void Choice::addValues(const char * const values[], uint8_t count)
|
||||
{
|
||||
this->values.reserve(this->values.size() + count);
|
||||
for (uint8_t i = 0; i < count; i++)
|
||||
this->values.emplace_back(values[i]);
|
||||
vmax += count;
|
||||
}
|
||||
|
||||
void Choice::setValues(std::vector<std::string> values)
|
||||
{
|
||||
this->values = std::move(values);
|
||||
}
|
||||
|
||||
void Choice::setValues(const char * const values[])
|
||||
{
|
||||
this->values.clear();
|
||||
if (values) {
|
||||
auto value = &values[0];
|
||||
for (int i = vmin; i <= vmax; i++) {
|
||||
this->values.emplace_back(*value++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Choice::setValue(int val)
|
||||
{
|
||||
if (_setValue) {
|
||||
_setValue(val);
|
||||
lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void Choice::onClicked()
|
||||
{
|
||||
openMenu();
|
||||
}
|
||||
|
||||
void Choice::fillMenu(Menu *menu, const FilterFct& filter)
|
||||
{
|
||||
menu->removeLines();
|
||||
auto value = _getValue();
|
||||
|
||||
int count = 0;
|
||||
int selectedIx = -1;
|
||||
for (int i = vmin; i <= vmax; ++i) {
|
||||
if (filter && !filter(i)) continue;
|
||||
if (isValueAvailable && !isValueAvailable(i)) continue;
|
||||
if (textHandler) {
|
||||
menu->addLineBuffered(textHandler(i), [=]() { setValue(i); });
|
||||
} else if (unsigned(i - vmin) < values.size()) {
|
||||
menu->addLineBuffered(values[i - vmin], [=]() { setValue(i); });
|
||||
} else {
|
||||
menu->addLineBuffered(std::to_string(i), [=]() { setValue(i); });
|
||||
}
|
||||
if (value == i) { selectedIx = count; }
|
||||
++count;
|
||||
}
|
||||
menu->updateLines();
|
||||
if (selectedIx >= 0) { menu->select(selectedIx); }
|
||||
}
|
||||
|
||||
void Choice::openMenu()
|
||||
{
|
||||
setEditMode(true); // this needs to be done first before menu is created.
|
||||
|
||||
auto menu = new Menu(this);
|
||||
if (!menuTitle.empty()) menu->setTitle(menuTitle);
|
||||
|
||||
fillMenu(menu);
|
||||
|
||||
if (beforeDisplayMenuHandler) {
|
||||
beforeDisplayMenuHandler(menu);
|
||||
}
|
||||
|
||||
menu->setCloseHandler([=]() { setEditMode(false); });
|
||||
}
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "form.h"
|
||||
|
||||
class Menu;
|
||||
|
||||
constexpr int CHOICE_LABEL_MARGIN_RIGHT = 10;
|
||||
|
||||
enum ChoiceType {
|
||||
CHOICE_TYPE_DROPOWN,
|
||||
CHOICE_TYPE_FOLDER,
|
||||
};
|
||||
|
||||
class ChoiceBase : public FormField
|
||||
{
|
||||
public:
|
||||
ChoiceBase(Window *parent, const rect_t &rect,
|
||||
ChoiceType type = CHOICE_TYPE_DROPOWN,
|
||||
WindowFlags windowFlags = 0);
|
||||
|
||||
inline ChoiceType getType() const { return type; }
|
||||
|
||||
protected:
|
||||
ChoiceType type;
|
||||
lv_obj_t* label;
|
||||
|
||||
friend void choice_changed_cb(lv_event_t *e);
|
||||
virtual std::string getLabelText() { return ""; };
|
||||
};
|
||||
|
||||
class Choice: public ChoiceBase {
|
||||
public:
|
||||
Choice(Window* parent, const rect_t &rect, int vmin, int vmax,
|
||||
std::function<int()> _getValue,
|
||||
std::function<void(int)> _setValue = nullptr,
|
||||
WindowFlags windowFlags = 0);
|
||||
Choice(Window* parent, const rect_t &rect,
|
||||
std::vector<std::string> values, int vmin, int vmax,
|
||||
std::function<int()> _getValue,
|
||||
std::function<void(int)> _setValue = nullptr,
|
||||
WindowFlags windowFlags = 0);
|
||||
Choice(Window* parent, const rect_t &rect, const char *const values[],
|
||||
int vmin, int vmax, std::function<int()> _getValue,
|
||||
std::function<void(int)> _setValue = nullptr,
|
||||
WindowFlags windowFlags = 0);
|
||||
Choice(Window* parent, const rect_t &rect, const char *values, int vmin,
|
||||
int vmax, std::function<int()> _getValue,
|
||||
std::function<void(int)> _setValue = nullptr,
|
||||
WindowFlags windowFlags = 0);
|
||||
|
||||
void addValue(const char *value);
|
||||
|
||||
void addValues(const char *const values[], uint8_t count);
|
||||
|
||||
void setValues(std::vector<std::string> values);
|
||||
|
||||
void setValues(const char *const values[]);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "Choice";
|
||||
}
|
||||
#endif
|
||||
|
||||
void onClicked() override;
|
||||
|
||||
void setBeforeDisplayMenuHandler(std::function<void(Menu*)> handler)
|
||||
{
|
||||
beforeDisplayMenuHandler = std::move(handler);
|
||||
}
|
||||
|
||||
void setSetValueHandler(std::function<void(int)> handler)
|
||||
{
|
||||
_setValue = std::move(handler);
|
||||
}
|
||||
|
||||
void setGetValueHandler(std::function<int()> handler)
|
||||
{
|
||||
_getValue = std::move(handler);
|
||||
}
|
||||
|
||||
void setAvailableHandler(std::function<bool(int)> handler)
|
||||
{
|
||||
isValueAvailable = std::move(handler);
|
||||
}
|
||||
|
||||
unsigned getIndexFromValue(int value) const
|
||||
{
|
||||
if (!isValueAvailable) {
|
||||
return value - vmin;
|
||||
}
|
||||
|
||||
unsigned index = 0;
|
||||
for (int i = vmin; i < value; i++) {
|
||||
if (isValueAvailable(i)) {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
int getValueFromIndex(int index) const
|
||||
{
|
||||
if (!isValueAvailable) {
|
||||
return vmin + index;
|
||||
}
|
||||
|
||||
int value = vmin - 1;
|
||||
while (index >= 0) {
|
||||
index--;
|
||||
value++;
|
||||
while (value < vmax && !isValueAvailable(value)) {
|
||||
value++;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void setValue(int val);
|
||||
int getIntValue() const { return _getValue(); }
|
||||
|
||||
unsigned getValuesCount() const
|
||||
{
|
||||
return getIndexFromValue(vmax + 1);
|
||||
}
|
||||
|
||||
void setTextHandler(std::function<std::string(int)> handler)
|
||||
{
|
||||
textHandler = std::move(handler);
|
||||
lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
}
|
||||
|
||||
void setMenuTitle(std::string value)
|
||||
{
|
||||
menuTitle = std::move(value);
|
||||
}
|
||||
|
||||
void setMin(int value)
|
||||
{
|
||||
vmin = value;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void setMax(int value)
|
||||
{
|
||||
vmax = value;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class MenuToolbar;
|
||||
|
||||
std::string getLabelText() override;
|
||||
std::vector<std::string> values;
|
||||
int vmin = 0;
|
||||
int vmax = 0;
|
||||
std::string menuTitle;
|
||||
std::function<int()> _getValue;
|
||||
std::function<void(int)> _setValue;
|
||||
std::function<bool(int)> isValueAvailable;
|
||||
std::function<std::string(int)> textHandler;
|
||||
std::function <void(Menu *)> beforeDisplayMenuHandler;
|
||||
|
||||
typedef std::function<bool(int16_t)> FilterFct;
|
||||
void fillMenu(Menu *menu, const FilterFct& filter = nullptr);
|
||||
|
||||
virtual void openMenu();
|
||||
};
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include "choiceex.h"
|
||||
|
||||
static void localLongPressHandler(lv_event_t* e)
|
||||
{
|
||||
lv_eventData_t* ld = (lv_eventData_t*)lv_event_get_user_data(e);
|
||||
ld->isLongPressed = true;
|
||||
ld->lv_LongPressHandler(ld->userData);
|
||||
}
|
||||
|
||||
void ChoiceEx::set_lv_LongPressHandler(lvHandler_t longPressHandler, void* data)
|
||||
{
|
||||
TRACE("longPressHandler=%p", longPressHandler);
|
||||
|
||||
if (longPressHandler) {
|
||||
longPressData.userData = data;
|
||||
longPressData.lv_LongPressHandler = longPressHandler;
|
||||
lv_obj_add_event_cb(lvobj, localLongPressHandler, LV_EVENT_LONG_PRESSED,
|
||||
&longPressData);
|
||||
lv_obj_add_event_cb(lvobj, ClickHandler, LV_EVENT_CLICKED, this);
|
||||
}
|
||||
}
|
||||
|
||||
ChoiceEx::ChoiceEx(Window* parent, const rect_t& rect, int16_t vmin,
|
||||
int16_t vmax, std::function<int16_t()> getValue,
|
||||
std::function<void(int16_t)> setValue,
|
||||
WindowFlags windowFlags) :
|
||||
Choice(parent, rect, vmin, vmax, getValue, setValue, windowFlags)
|
||||
{
|
||||
longPressData.isLongPressed = false;
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef _CHOICEEX_H_
|
||||
#define _CHOICEEX_H_
|
||||
#include "choice.h"
|
||||
|
||||
typedef void (*lvHandler_t)(void*);
|
||||
typedef struct {
|
||||
void* userData;
|
||||
bool isLongPressed;
|
||||
lvHandler_t lv_LongPressHandler;
|
||||
} lv_eventData_t;
|
||||
|
||||
class ChoiceEx : public Choice
|
||||
{
|
||||
public:
|
||||
ChoiceEx(Window* parent, const rect_t& rect, int16_t vmin, int16_t vmax,
|
||||
std::function<int16_t()> getValue,
|
||||
std::function<void(int16_t)> setValue = nullptr,
|
||||
WindowFlags windowFlags = 0);
|
||||
|
||||
void set_lv_LongPressHandler(lvHandler_t longPressHandler, void* data);
|
||||
|
||||
lv_eventData_t longPressData;
|
||||
|
||||
void onClicked() override
|
||||
{
|
||||
if (!longPressData.isLongPressed) Choice::onClicked();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::function<void(event_t)> longPressHandler = nullptr;
|
||||
|
||||
static void ClickHandler(lv_event_t* e)
|
||||
{
|
||||
ChoiceEx* ch = (ChoiceEx*)lv_event_get_user_data(e);
|
||||
if (ch) ch->longPressData.isLongPressed = false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "dialog.h"
|
||||
#include "mainwindow.h"
|
||||
#include "theme.h"
|
||||
|
||||
DialogWindowContent::DialogWindowContent(Dialog* parent, const rect_t& rect) :
|
||||
ModalWindowContent(parent, rect),
|
||||
form(this, rect_t{})
|
||||
{
|
||||
form.setFlexLayout();
|
||||
|
||||
auto form_obj = form.getLvObj();
|
||||
lv_obj_set_style_pad_all(form_obj, lv_dpx(8), 0);
|
||||
|
||||
lv_coord_t max_height = LCD_H * 0.8;
|
||||
lv_obj_set_style_max_height(form_obj, max_height, 0);
|
||||
}
|
||||
|
||||
void DialogWindowContent::setTitle(const std::string& text)
|
||||
{
|
||||
ModalWindowContent::setTitle(text);
|
||||
if (title) {
|
||||
lv_coord_t title_h = lv_obj_get_height(title);
|
||||
lv_obj_set_y(form.getLvObj(), title_h);
|
||||
}
|
||||
}
|
||||
|
||||
void DialogWindowContent::deleteLater(bool detach, bool trash)
|
||||
{
|
||||
if (_deleted) return;
|
||||
form.deleteLater(true, false);
|
||||
ModalWindowContent::deleteLater(detach, trash);
|
||||
}
|
||||
|
||||
void DialogWindowContent::updateSize()
|
||||
{
|
||||
lv_obj_center(lvobj);
|
||||
ModalWindowContent::updateSize();
|
||||
}
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string DialogWindowContent::getName() const
|
||||
{
|
||||
return "DialogWindowContent";
|
||||
}
|
||||
#endif
|
||||
|
||||
Dialog::Dialog(Window* parent, std::string title, const rect_t& rect) :
|
||||
ModalWindow(parent), content(new DialogWindowContent(this, rect))
|
||||
{
|
||||
lv_obj_set_style_bg_color(content->getLvObj(), makeLvColor(COLOR_THEME_SECONDARY3), 0);
|
||||
lv_obj_set_style_bg_opa(content->getLvObj(), LV_OPA_100, LV_PART_MAIN);
|
||||
bringToTop();
|
||||
if (!title.empty()) content->setTitle(std::move(title));
|
||||
}
|
||||
|
||||
void Dialog::onCancel()
|
||||
{
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
void Dialog::onEvent(event_t event)
|
||||
{
|
||||
// block key events
|
||||
(void)event;
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "modal_window.h"
|
||||
#include "form.h"
|
||||
|
||||
class Dialog;
|
||||
|
||||
class DialogWindowContent : public ModalWindowContent
|
||||
{
|
||||
friend class Dialog;
|
||||
|
||||
public:
|
||||
DialogWindowContent(Dialog* parent, const rect_t& rect);
|
||||
|
||||
void setTitle(const std::string& text) override;
|
||||
|
||||
void deleteLater(bool detach = true, bool trash = true) override;
|
||||
void updateSize() override;
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override;
|
||||
#endif
|
||||
|
||||
public:
|
||||
FormGroup form;
|
||||
};
|
||||
|
||||
class Dialog : public ModalWindow
|
||||
{
|
||||
public:
|
||||
Dialog(Window* parent, std::string title, const rect_t& rect);
|
||||
|
||||
protected:
|
||||
DialogWindowContent* content;
|
||||
|
||||
void onCancel() override;
|
||||
void onEvent(event_t event) override;
|
||||
};
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "filechoice.h"
|
||||
#include "libopenui_file.h"
|
||||
#include "menu.h"
|
||||
#include "theme.h"
|
||||
#include "message_dialog.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#if !defined(STR_SDCARD)
|
||||
#define STR_SDCARD "SD"
|
||||
#endif
|
||||
|
||||
#if !defined(STR_NO_FILES_ON_SD)
|
||||
#define STR_NO_FILES_ON_SD "No files on SD Card!"
|
||||
#endif
|
||||
|
||||
FileChoice::FileChoice(Window* parent, const rect_t &rect,
|
||||
std::string folder, const char *extension, int maxlen,
|
||||
std::function<std::string()> getValue,
|
||||
std::function<void(std::string)> setValue,
|
||||
bool stripExtension) :
|
||||
ChoiceBase(parent, rect, CHOICE_TYPE_FOLDER),
|
||||
folder(std::move(folder)),
|
||||
extension(extension),
|
||||
maxlen(maxlen),
|
||||
getValue(std::move(getValue)),
|
||||
setValue(std::move(setValue)),
|
||||
stripExtension(stripExtension)
|
||||
{
|
||||
lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
}
|
||||
|
||||
std::string FileChoice::getLabelText()
|
||||
{
|
||||
return getValue();
|
||||
}
|
||||
|
||||
|
||||
bool FileChoice::openMenu()
|
||||
{
|
||||
FILINFO fno;
|
||||
DIR dir;
|
||||
std::list<std::string> files;
|
||||
const char *fnExt;
|
||||
uint8_t fnLen, extLen;
|
||||
|
||||
FRESULT res = f_opendir(&dir, folder.c_str()); // Open the directory
|
||||
if (res == FR_OK) {
|
||||
bool firstTime = true;
|
||||
for (;;) {
|
||||
res = sdReadDir(&dir, &fno, firstTime);
|
||||
if (res != FR_OK || fno.fname[0] == 0)
|
||||
break; // break on error or end of dir
|
||||
if (fno.fattrib & AM_DIR) continue; // skip subfolders
|
||||
if (fno.fattrib & AM_HID) continue; // skip hidden files
|
||||
if (fno.fattrib & AM_SYS) continue; // skip system files
|
||||
|
||||
fnExt = getFileExtension(fno.fname, 0, 0, &fnLen, &extLen);
|
||||
|
||||
if (extension && (!fnExt || !isExtensionMatching(fnExt, extension)))
|
||||
continue; // wrong extension
|
||||
|
||||
if (stripExtension) fnLen -= extLen;
|
||||
|
||||
if (!fnLen || fnLen > maxlen) continue; // wrong size
|
||||
|
||||
// eject duplicates
|
||||
std::string newFile(fno.fname, fnLen);
|
||||
if (std::find(files.begin(), files.end(), newFile) != files.end())
|
||||
continue;
|
||||
|
||||
files.emplace_back(newFile);
|
||||
}
|
||||
|
||||
if (!files.empty()) {
|
||||
// sort files
|
||||
files.sort(compare_nocase);
|
||||
files.push_front("");
|
||||
|
||||
auto menu = new Menu(this);
|
||||
int count = 0;
|
||||
int current = -1;
|
||||
std::string value = getValue();
|
||||
for (const auto &file : files) {
|
||||
menu->addLineBuffered(file, [=]() {
|
||||
setValue(file);
|
||||
lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
});
|
||||
// TRACE("%s %d %s %d", value.c_str(), value.size(), file.c_str(),
|
||||
// file.size());
|
||||
if (value.compare(file) == 0) {
|
||||
// TRACE("OK");
|
||||
current = count;
|
||||
}
|
||||
++count;
|
||||
}
|
||||
menu->updateLines();
|
||||
|
||||
if (current >= 0) {
|
||||
menu->select(current);
|
||||
}
|
||||
|
||||
menu->setCloseHandler([=]() {
|
||||
editMode = false;
|
||||
// setFocus(SET_FOCUS_DEFAULT);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
new MessageDialog(this, STR_SDCARD, STR_NO_FILES_ON_SD);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FileChoice::onClicked()
|
||||
{
|
||||
openMenu();
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "choice.h"
|
||||
#include <string>
|
||||
|
||||
class FileChoice : public ChoiceBase
|
||||
{
|
||||
public:
|
||||
FileChoice(Window* parent, const rect_t& rect, std::string folder,
|
||||
const char* extension, int maxlen,
|
||||
std::function<std::string()> getValue,
|
||||
std::function<void(std::string)> setValue,
|
||||
bool stripExtension=false);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override { return "FileChoice"; }
|
||||
#endif
|
||||
|
||||
void onClicked() override;
|
||||
|
||||
protected:
|
||||
std::string getLabelText() override;
|
||||
std::string folder;
|
||||
const char* extension;
|
||||
int maxlen;
|
||||
std::function<std::string()> getValue;
|
||||
std::function<void(std::string)> setValue;
|
||||
bool stripExtension;
|
||||
|
||||
bool openMenu();
|
||||
};
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
class FlexGridLayout
|
||||
{
|
||||
const lv_coord_t* col_dsc = nullptr;
|
||||
const lv_coord_t* row_dsc = nullptr;
|
||||
lv_coord_t padding = 0;
|
||||
|
||||
uint8_t col_pos = 0;
|
||||
uint8_t col_span = 1;
|
||||
uint8_t row_pos = 0;
|
||||
uint8_t row_span = 1;
|
||||
|
||||
public:
|
||||
FlexGridLayout(const lv_coord_t col_dsc[], const lv_coord_t row_dsc[],
|
||||
lv_coord_t padding = 4) :
|
||||
col_dsc(col_dsc), row_dsc(row_dsc), padding(padding)
|
||||
{
|
||||
}
|
||||
|
||||
FlexGridLayout(const FlexGridLayout& g) :
|
||||
col_dsc(g.col_dsc), row_dsc(g.row_dsc), padding(g.padding)
|
||||
{
|
||||
}
|
||||
|
||||
void apply(Window* w) { apply(w->getLvObj()); }
|
||||
|
||||
void apply(lv_obj_t* obj) {
|
||||
|
||||
// padding
|
||||
lv_obj_set_style_pad_all(obj, padding, LV_PART_MAIN);
|
||||
lv_obj_set_style_pad_row(obj, padding, LV_PART_MAIN);
|
||||
lv_obj_set_style_pad_column(obj, padding, LV_PART_MAIN);
|
||||
|
||||
// layout
|
||||
lv_obj_set_layout(obj, LV_LAYOUT_GRID);
|
||||
if (col_dsc && row_dsc) {
|
||||
lv_obj_set_grid_dsc_array(obj, col_dsc, row_dsc);
|
||||
}
|
||||
}
|
||||
|
||||
void add(Window* w) { add(w->getLvObj()); }
|
||||
|
||||
void add(lv_obj_t* obj) {
|
||||
if (col_dsc && row_dsc) {
|
||||
lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_START, col_pos, col_span,
|
||||
LV_GRID_ALIGN_CENTER, row_pos, row_span);
|
||||
}
|
||||
}
|
||||
|
||||
void resetPos() { col_pos = 0; row_pos = 0; }
|
||||
|
||||
void nextColumn() { col_pos += col_span; }
|
||||
void nextRow() { row_pos += row_span; col_pos = 0; }
|
||||
|
||||
void nextCell()
|
||||
{
|
||||
nextColumn();
|
||||
if (col_dsc[col_pos] == LV_GRID_TEMPLATE_LAST) {
|
||||
nextRow();
|
||||
}
|
||||
}
|
||||
|
||||
void setColSpan(uint8_t span) { col_span = span; }
|
||||
void setRowSpan(uint8_t span) { row_span = span; }
|
||||
};
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
#include "libopenui_types.h"
|
||||
|
||||
const lv_font_t* getFont(LcdFlags flags);
|
||||
uint8_t getFontHeight(LcdFlags flags);
|
||||
uint8_t getFontHeightCondensed(LcdFlags flags);
|
||||
int getTextWidth(const char * s, int len = 0, LcdFlags flags = 0);
|
||||
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "form.h"
|
||||
#include "bitmapbuffer.h"
|
||||
#include "libopenui_config.h"
|
||||
|
||||
#include "widgets/window_base.h"
|
||||
|
||||
FormField::FormField(Window* parent, const rect_t& rect,
|
||||
WindowFlags windowFlags, LcdFlags textFlags,
|
||||
LvglCreate objConstruct) :
|
||||
Window(parent, rect, windowFlags, textFlags, objConstruct)
|
||||
{
|
||||
lv_obj_add_flag(lvobj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
|
||||
}
|
||||
|
||||
void FormField::setEditMode(bool newEditMode)
|
||||
{
|
||||
editMode = newEditMode;
|
||||
|
||||
if (lvobj != nullptr) {
|
||||
lv_group_t* grp = (lv_group_t*)lv_obj_get_group(lvobj);
|
||||
if (grp != nullptr) lv_group_set_editing(grp, editMode);
|
||||
}
|
||||
|
||||
if (editMode && lvobj != nullptr) {
|
||||
lv_obj_add_state(lvobj, LV_STATE_EDITED);
|
||||
} else if (lvobj != nullptr) {
|
||||
lv_obj_clear_state(lvobj, LV_STATE_EDITED);
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void FormField::enable(bool value)
|
||||
{
|
||||
if (value) {
|
||||
lv_obj_clear_state(lvobj, LV_STATE_DISABLED);
|
||||
} else {
|
||||
lv_obj_add_state(lvobj, LV_STATE_DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
bool FormField::isEnabled() const
|
||||
{
|
||||
return !lv_obj_has_state(lvobj, LV_STATE_DISABLED);
|
||||
}
|
||||
|
||||
void FormField::onClicked()
|
||||
{
|
||||
lv_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act());
|
||||
if(indev_type != LV_INDEV_TYPE_POINTER) {
|
||||
setEditMode(!editMode);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void FormField::onCancel()
|
||||
{
|
||||
if (isEditMode()) {
|
||||
setEditMode(false);
|
||||
invalidate();
|
||||
} else {
|
||||
Window::onCancel();
|
||||
}
|
||||
}
|
||||
|
||||
FormGroup::Line::Line(Window* parent, lv_obj_t* obj, FlexGridLayout* layout) :
|
||||
Window(parent, obj), layout(layout)
|
||||
{
|
||||
construct();
|
||||
}
|
||||
|
||||
FormGroup::Line::Line(Window* parent, FlexGridLayout* layout) :
|
||||
Window(parent, rect_t{}), layout(layout)
|
||||
{
|
||||
construct();
|
||||
}
|
||||
|
||||
void FormGroup::Line::construct()
|
||||
{
|
||||
// forward scroll and focus
|
||||
windowFlags |= FORWARD_SCROLL | NO_FOCUS | FORM_FORWARD_FOCUS;
|
||||
lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICK_FOCUSABLE);
|
||||
|
||||
if (layout) {
|
||||
layout->apply(lvobj);
|
||||
}
|
||||
|
||||
lv_obj_set_height(lvobj, LV_SIZE_CONTENT);
|
||||
lv_obj_set_width(lvobj, lv_pct(100));
|
||||
}
|
||||
|
||||
void FormGroup::Line::setLayout(FlexGridLayout *l)
|
||||
{
|
||||
layout = l;
|
||||
if (layout) layout->apply(lvobj);
|
||||
}
|
||||
|
||||
void FormGroup::Line::addChild(Window* window)
|
||||
{
|
||||
Window::addChild(window);
|
||||
if (layout) {
|
||||
layout->add(window->getLvObj());
|
||||
layout->nextCell();
|
||||
}
|
||||
}
|
||||
|
||||
FormGroup::FormGroup(Window* parent, const rect_t& rect,
|
||||
WindowFlags windowflags, LvglCreate objConstruct) :
|
||||
Window(parent, rect, windowflags, 0, objConstruct)
|
||||
{
|
||||
lv_obj_set_style_bg_opa(lvobj, LV_OPA_TRANSP, LV_PART_MAIN);
|
||||
}
|
||||
|
||||
void FormGroup::setFlexLayout(lv_flex_flow_t flow, lv_coord_t padding)
|
||||
{
|
||||
lv_obj_set_flex_flow(lvobj, flow);
|
||||
if (_LV_FLEX_COLUMN & flow) {
|
||||
lv_obj_set_style_pad_row(lvobj, padding, LV_PART_MAIN);
|
||||
} else {
|
||||
lv_obj_set_style_pad_column(lvobj, padding, LV_PART_MAIN);
|
||||
}
|
||||
lv_obj_set_width(lvobj, lv_pct(100));
|
||||
lv_obj_set_height(lvobj, LV_SIZE_CONTENT);
|
||||
}
|
||||
|
||||
FormGroup::Line* FormGroup::newLine(FlexGridLayout* layout, lv_coord_t left_padding)
|
||||
{
|
||||
if (layout) layout->resetPos();
|
||||
auto lv_line = window_create(lvobj);
|
||||
if (left_padding) lv_obj_set_style_pad_left(lv_line, left_padding, 0);
|
||||
return new Line(this, lv_line, layout);
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "window.h"
|
||||
#include "flexlayout.h"
|
||||
|
||||
constexpr WindowFlags FORM_FORWARD_FOCUS = WINDOW_FLAGS_LAST << 1;
|
||||
constexpr WindowFlags FORM_DETACHED = WINDOW_FLAGS_LAST << 2;
|
||||
constexpr WindowFlags FORM_BORDER_FOCUS_ONLY = WINDOW_FLAGS_LAST << 3;
|
||||
constexpr WindowFlags FORM_NO_BORDER = WINDOW_FLAGS_LAST << 4;
|
||||
constexpr WindowFlags FORM_FLAGS_LAST = FORM_NO_BORDER;
|
||||
|
||||
class FormField : public Window
|
||||
{
|
||||
public:
|
||||
FormField(Window *parent, const rect_t &rect, WindowFlags windowFlags = 0,
|
||||
LcdFlags textFlags = 0, LvglCreate objConstruct = nullptr);
|
||||
|
||||
virtual void changeEnd(bool forceChanged = false)
|
||||
{
|
||||
if (changeHandler) { changeHandler(); }
|
||||
}
|
||||
|
||||
void setChangeHandler(std::function<void()> handler)
|
||||
{
|
||||
changeHandler = std::move(handler);
|
||||
}
|
||||
|
||||
void setBackgroundHandler(std::function<uint32_t(FormField *field)> handler)
|
||||
{
|
||||
backgroundHandler = std::move(handler);
|
||||
}
|
||||
|
||||
inline bool isEditMode() const { return editMode; }
|
||||
virtual void setEditMode(bool newEditMode);
|
||||
|
||||
bool isEnabled() const;
|
||||
void enable(bool value = true);
|
||||
void disable() { enable(false); }
|
||||
|
||||
void onFocusLost() override
|
||||
{
|
||||
setEditMode(false);
|
||||
Window::onFocusLost();
|
||||
}
|
||||
|
||||
void onClicked() override;
|
||||
void onCancel() override;
|
||||
|
||||
protected:
|
||||
bool editMode = false;
|
||||
bool enabled = true;
|
||||
std::function<void()> changeHandler = nullptr;
|
||||
std::function<uint32_t(FormField *)> backgroundHandler = nullptr;
|
||||
};
|
||||
|
||||
class FormGroup : public Window
|
||||
{
|
||||
public:
|
||||
class Line : public Window
|
||||
{
|
||||
FlexGridLayout *layout;
|
||||
void construct();
|
||||
|
||||
public:
|
||||
Line(Window *parent, lv_obj_t *obj, FlexGridLayout *layout = nullptr);
|
||||
Line(Window *parent, FlexGridLayout *layout = nullptr);
|
||||
|
||||
void setLayout(FlexGridLayout *l);
|
||||
|
||||
protected:
|
||||
void addChild(Window *window) override;
|
||||
};
|
||||
|
||||
FormGroup(Window *parent, const rect_t &rect, WindowFlags windowflags = 0,
|
||||
LvglCreate objConstruct = nullptr);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override { return "FormGroup"; }
|
||||
#endif
|
||||
|
||||
void setFlexLayout(lv_flex_flow_t flow = LV_FLEX_FLOW_COLUMN, lv_coord_t padding = 0);
|
||||
Line* newLine(FlexGridLayout* layout = nullptr, lv_coord_t left_padding = 0);
|
||||
};
|
||||
|
||||
class FormWindow : public FormGroup
|
||||
{
|
||||
public:
|
||||
FormWindow(Window *parent, const rect_t &rect, WindowFlags windowFlags = 0,
|
||||
LvglCreate objConstruct = nullptr) :
|
||||
FormGroup(parent, rect, windowFlags, objConstruct)
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override { return "FormWindow"; }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void paint(BitmapBuffer *) override {}
|
||||
};
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "window.h"
|
||||
|
||||
class GridLayout {
|
||||
public:
|
||||
explicit GridLayout(coord_t width, coord_t top = 0):
|
||||
width(width),
|
||||
currentY(top)
|
||||
{
|
||||
}
|
||||
|
||||
explicit GridLayout(Window * window):
|
||||
width(window->width())
|
||||
{
|
||||
}
|
||||
|
||||
rect_t getSlot(uint8_t count = 1, uint8_t index = 0) const
|
||||
{
|
||||
coord_t width = (this->width - (count - 1) * PAGE_LINE_SPACING) / count;
|
||||
coord_t left = (width + PAGE_LINE_SPACING) * index;
|
||||
return {left, currentY, width, PAGE_LINE_HEIGHT};
|
||||
}
|
||||
|
||||
void spacer(coord_t height=PAGE_LINE_SPACING)
|
||||
{
|
||||
currentY += height;
|
||||
}
|
||||
|
||||
void nextLine(coord_t height=PAGE_LINE_HEIGHT)
|
||||
{
|
||||
spacer(height + PAGE_LINE_SPACING);
|
||||
}
|
||||
|
||||
void addWindow(Window * window)
|
||||
{
|
||||
window->adjustHeight();
|
||||
currentY += window->rect.h + PAGE_LINE_SPACING;
|
||||
}
|
||||
|
||||
coord_t getWindowHeight() const
|
||||
{
|
||||
return currentY;
|
||||
}
|
||||
|
||||
protected:
|
||||
coord_t width;
|
||||
coord_t currentY = 0;
|
||||
};
|
||||
|
||||
class FormGridLayout: public GridLayout {
|
||||
public:
|
||||
explicit FormGridLayout(coord_t width = LCD_W, coord_t top = 0):
|
||||
GridLayout(width, top)
|
||||
{
|
||||
}
|
||||
|
||||
void setLabelWidth(coord_t value)
|
||||
{
|
||||
labelWidth = value;
|
||||
}
|
||||
|
||||
void setMarginLeft(coord_t value)
|
||||
{
|
||||
lineMarginLeft = value;
|
||||
}
|
||||
|
||||
void setMarginRight(coord_t value)
|
||||
{
|
||||
lineMarginRight = value;
|
||||
}
|
||||
|
||||
rect_t getLineSlot()
|
||||
{
|
||||
return { lineMarginLeft, currentY, this->width - lineMarginRight - lineMarginLeft, PAGE_LINE_HEIGHT };
|
||||
}
|
||||
|
||||
rect_t getCenteredSlot(coord_t width = 0 ) const
|
||||
{
|
||||
if (width == 0)
|
||||
width = this->width;
|
||||
return { lineMarginLeft + (this->width - width)/2, currentY, min(width, this->width - lineMarginRight - lineMarginLeft), PAGE_LINE_HEIGHT };
|
||||
}
|
||||
|
||||
rect_t getLabelSlot(bool indent = false) const
|
||||
{
|
||||
coord_t left = indent ? lineMarginLeft + PAGE_INDENT_WIDTH : lineMarginLeft;
|
||||
return { left, currentY, labelWidth - left, PAGE_LINE_HEIGHT };
|
||||
}
|
||||
|
||||
rect_t getFieldSlot(uint8_t count = 1, uint8_t index = 0) const
|
||||
{
|
||||
coord_t width = (this->width - labelWidth - lineMarginRight - (count - 1) * PAGE_LINE_SPACING) / count;
|
||||
coord_t left = labelWidth + (width + PAGE_LINE_SPACING) * index;
|
||||
return {left, currentY, width, PAGE_LINE_HEIGHT};
|
||||
}
|
||||
|
||||
protected:
|
||||
coord_t labelWidth = PAGE_LABEL_WIDTH;
|
||||
coord_t lineMarginLeft = PAGE_PADDING;
|
||||
coord_t lineMarginRight = PAGE_PADDING;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/edgetx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
#include "keyboard_base.h"
|
||||
|
||||
#include "form.h"
|
||||
#include "mainwindow.h"
|
||||
|
||||
Keyboard * Keyboard::activeKeyboard = nullptr;
|
||||
|
||||
static void keyboard_event_cb(lv_event_t * e)
|
||||
{
|
||||
auto code = lv_event_get_code(e);
|
||||
if (code == LV_EVENT_READY) {
|
||||
Keyboard::hide();
|
||||
} else if (code == LV_EVENT_CANCEL) {
|
||||
Keyboard::hide();
|
||||
} else if (code == LV_EVENT_KEY) {
|
||||
int32_t c = *((int32_t *)lv_event_get_param(e));
|
||||
if (c == LV_KEY_ESC) {
|
||||
Keyboard::hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void field_focus_leave(lv_event_t* e)
|
||||
{
|
||||
Keyboard::hide();
|
||||
}
|
||||
|
||||
static void _assign_lv_group(lv_group_t* g)
|
||||
{
|
||||
// associate it with all input devices
|
||||
lv_indev_t* indev = lv_indev_get_next(NULL);
|
||||
while (indev) {
|
||||
lv_indev_set_group(indev, g);
|
||||
indev = lv_indev_get_next(indev);
|
||||
}
|
||||
}
|
||||
|
||||
Keyboard::Keyboard(coord_t height) :
|
||||
Window(MainWindow::instance(), {0, LCD_H - height, LCD_W, height}, OPAQUE)
|
||||
{
|
||||
// set the background of the window and opacity to 100%
|
||||
lv_obj_set_parent(lvobj, lv_layer_top()); // the keyboard is always on top
|
||||
lv_obj_set_style_bg_color(lvobj, lv_color_make(0xE0, 0xE0, 0xE0), LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_opa(lvobj, LV_OPA_100, LV_PART_MAIN);
|
||||
|
||||
// use a separate group for the keyboard
|
||||
group = lv_group_create();
|
||||
lv_group_set_editing(group, true);
|
||||
|
||||
auto old_g = lv_group_get_default();
|
||||
lv_group_set_default(group);
|
||||
|
||||
keyboard = lv_keyboard_create(lvobj);
|
||||
lv_group_set_default(old_g);
|
||||
|
||||
lv_obj_add_event_cb(keyboard, keyboard_event_cb, LV_EVENT_ALL, this);
|
||||
|
||||
lv_obj_set_pos(keyboard, 0, 0);
|
||||
lv_obj_set_size(keyboard, LCD_W, height);
|
||||
|
||||
// TODO: really needed ???
|
||||
lv_obj_clear_flag(keyboard, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
Keyboard::~Keyboard()
|
||||
{
|
||||
if (group) lv_group_del(group);
|
||||
}
|
||||
|
||||
void Keyboard::clearField()
|
||||
{
|
||||
TRACE("CLEAR FIELD");
|
||||
if (keyboard != nullptr) {
|
||||
lv_obj_add_flag(keyboard, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
detach();
|
||||
lv_obj_set_parent(lvobj, lv_layer_top());
|
||||
|
||||
if (fieldContainer) {
|
||||
lv_obj_scroll_to_y(fieldContainer->getLvObj(), scroll_pos, LV_ANIM_OFF);
|
||||
fieldContainer = nullptr;
|
||||
}
|
||||
|
||||
if (field) {
|
||||
// restore field's group
|
||||
auto obj = field->getLvObj();
|
||||
if (obj) {
|
||||
lv_obj_remove_event_cb(obj, field_focus_leave);
|
||||
}
|
||||
|
||||
field->setEditMode(false);
|
||||
field->changeEnd();
|
||||
field = nullptr;
|
||||
|
||||
if (fieldGroup) {
|
||||
_assign_lv_group(fieldGroup);
|
||||
lv_group_set_editing(fieldGroup, false);
|
||||
fieldGroup = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Keyboard::hide()
|
||||
{
|
||||
if (activeKeyboard) {
|
||||
activeKeyboard->clearField();
|
||||
lv_obj_add_flag(activeKeyboard->lvobj, LV_OBJ_FLAG_HIDDEN);
|
||||
activeKeyboard = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool Keyboard::attachKeyboard()
|
||||
{
|
||||
if (activeKeyboard) {
|
||||
if (activeKeyboard == this) return false;
|
||||
hide();
|
||||
}
|
||||
|
||||
activeKeyboard = this;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Keyboard::setField(FormField* newField)
|
||||
{
|
||||
if (!attachKeyboard())
|
||||
return;
|
||||
|
||||
lv_obj_t* obj = newField->getLvObj();
|
||||
if (obj) {
|
||||
|
||||
fieldContainer = newField->getFullScreenWindow();
|
||||
if (fieldContainer) {
|
||||
|
||||
attach(fieldContainer);
|
||||
|
||||
lv_area_t coords;
|
||||
lv_obj_get_coords(obj, &coords);
|
||||
|
||||
// place keyboard bellow the field with some margin
|
||||
setTop(max(coords.y2 + 21, LCD_H - height()));
|
||||
|
||||
// save scroll position
|
||||
scroll_pos = lv_obj_get_scroll_y(fieldContainer->getLvObj());
|
||||
lv_obj_scroll_to_view(lvobj, LV_ANIM_OFF);
|
||||
|
||||
invalidate();
|
||||
newField->setEditMode(true);
|
||||
|
||||
lv_keyboard_set_textarea(keyboard, obj);
|
||||
lv_obj_add_event_cb(obj, field_focus_leave, LV_EVENT_DEFOCUSED, nullptr);
|
||||
_assign_lv_group(group);
|
||||
|
||||
field = newField;
|
||||
fieldGroup = (lv_group_t*)lv_obj_get_group(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/edgetx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "window.h"
|
||||
|
||||
class FormField;
|
||||
|
||||
class Keyboard : public Window
|
||||
{
|
||||
public:
|
||||
explicit Keyboard(coord_t height);
|
||||
~Keyboard();
|
||||
|
||||
void clearField();
|
||||
static void hide();
|
||||
|
||||
protected:
|
||||
static Keyboard *activeKeyboard;
|
||||
|
||||
lv_group_t* group = nullptr;
|
||||
lv_obj_t* keyboard = nullptr;
|
||||
|
||||
FormField* field = nullptr;
|
||||
Window* fieldContainer = nullptr;
|
||||
lv_group_t* fieldGroup = nullptr;
|
||||
lv_coord_t scroll_pos = 0;
|
||||
|
||||
void setField(FormField* newField);
|
||||
bool attachKeyboard();
|
||||
};
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "keyboard_number.h"
|
||||
#include "numberedit.h"
|
||||
|
||||
constexpr coord_t KEYBOARD_HEIGHT = 90;
|
||||
NumberKeyboard * NumberKeyboard::_instance = nullptr;
|
||||
|
||||
static const char* number_kb_map[] = {
|
||||
"<<", "-", "+", ">>", "\n",
|
||||
"MIN", "DEF", "+/-", "MAX", ""
|
||||
};
|
||||
|
||||
#define LV_KB_BTN(width) LV_BTNMATRIX_CTRL_POPOVER | width
|
||||
#define LV_KB_CTRL(width) LV_KEYBOARD_CTRL_BTN_FLAGS | width
|
||||
|
||||
static const lv_btnmatrix_ctrl_t number_kb_ctrl_map[] = {
|
||||
LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4),
|
||||
LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_CTRL(4), LV_KB_BTN(4)
|
||||
};
|
||||
|
||||
static void on_key(lv_event_t* e)
|
||||
{
|
||||
lv_obj_t * obj = lv_event_get_target(e);
|
||||
NumberEdit* edit = (NumberEdit*)lv_event_get_user_data(e);
|
||||
if (!obj || !edit) return;
|
||||
|
||||
uint16_t btn_id = lv_btnmatrix_get_selected_btn(obj);
|
||||
if(btn_id == LV_BTNMATRIX_BTN_NONE) return;
|
||||
|
||||
const char * txt = lv_btnmatrix_get_btn_text(obj, lv_btnmatrix_get_selected_btn(obj));
|
||||
if(txt == NULL) return;
|
||||
|
||||
if (strcmp(txt, "<<") == 0) {
|
||||
edit->onEvent(EVT_VIRTUAL_KEY_BACKWARD);
|
||||
} else if (strcmp(txt, "-") == 0) {
|
||||
edit->onEvent(EVT_VIRTUAL_KEY_MINUS);
|
||||
} else if (strcmp(txt, "+") == 0) {
|
||||
edit->onEvent(EVT_VIRTUAL_KEY_PLUS);
|
||||
} else if (strcmp(txt, ">>") == 0) {
|
||||
edit->onEvent(EVT_VIRTUAL_KEY_FORWARD);
|
||||
} else if (strcmp(txt, "MIN") == 0) {
|
||||
edit->onEvent(EVT_VIRTUAL_KEY_MIN);
|
||||
} else if (strcmp(txt, "DEF") == 0) {
|
||||
edit->onEvent(EVT_VIRTUAL_KEY_DEFAULT);
|
||||
} else if (strcmp(txt, "MAX") == 0) {
|
||||
edit->onEvent(EVT_VIRTUAL_KEY_MAX);
|
||||
} else if (strcmp(txt, "+/-") == 0) {
|
||||
edit->onEvent(EVT_VIRTUAL_KEY_SIGN);
|
||||
}
|
||||
}
|
||||
|
||||
NumberKeyboard::NumberKeyboard() :
|
||||
Keyboard(KEYBOARD_HEIGHT)
|
||||
{
|
||||
// setup custom keyboard
|
||||
lv_keyboard_set_map(keyboard, LV_KEYBOARD_MODE_USER_1,
|
||||
number_kb_map, number_kb_ctrl_map);
|
||||
|
||||
lv_keyboard_set_mode(keyboard, LV_KEYBOARD_MODE_USER_1);
|
||||
}
|
||||
|
||||
NumberKeyboard::~NumberKeyboard()
|
||||
{
|
||||
_instance = nullptr;
|
||||
}
|
||||
|
||||
void NumberKeyboard::show(NumberEdit* field)
|
||||
{
|
||||
if (!_instance) _instance = new NumberKeyboard();
|
||||
|
||||
lv_obj_clear_flag(_instance->lvobj, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(_instance->keyboard, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
_instance->setField(field);
|
||||
|
||||
auto kb = _instance->keyboard;
|
||||
lv_keyboard_set_textarea(kb, nullptr);
|
||||
|
||||
lv_obj_remove_event_cb(kb, on_key);
|
||||
lv_obj_add_event_cb(kb, on_key, LV_EVENT_VALUE_CHANGED, field);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "keyboard_base.h"
|
||||
|
||||
class NumberEdit;
|
||||
|
||||
class NumberKeyboard : public Keyboard
|
||||
{
|
||||
public:
|
||||
NumberKeyboard();
|
||||
~NumberKeyboard() override;
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override { return "NumberKeyboard"; }
|
||||
#endif
|
||||
|
||||
static void show(NumberEdit* field);
|
||||
|
||||
protected:
|
||||
static NumberKeyboard* _instance;
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "keyboard_text.h"
|
||||
#include "textedit.h"
|
||||
#include "font.h"
|
||||
|
||||
constexpr coord_t KEYBOARD_HEIGHT = LCD_H * 2 / 5;
|
||||
TextKeyboard * TextKeyboard::_instance = nullptr;
|
||||
|
||||
TextKeyboard::TextKeyboard() :
|
||||
Keyboard(KEYBOARD_HEIGHT)
|
||||
{
|
||||
}
|
||||
|
||||
TextKeyboard::~TextKeyboard()
|
||||
{
|
||||
_instance = nullptr;
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void TextKeyboard::onEvent(event_t event)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
void TextKeyboard::show(FormField* field)
|
||||
{
|
||||
if (!_instance) _instance = new TextKeyboard();
|
||||
|
||||
lv_obj_clear_flag(_instance->lvobj, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(_instance->keyboard, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_keyboard_set_mode(_instance->keyboard, LV_KEYBOARD_MODE_TEXT_LOWER);
|
||||
|
||||
_instance->setField(field);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "keyboard_base.h"
|
||||
|
||||
#define KEYBOARD_SPACE "\t"
|
||||
#define KEYBOARD_ENTER "\n"
|
||||
#define KEYBOARD_BACKSPACE "\200"
|
||||
#define KEYBOARD_SET_UPPERCASE "\201"
|
||||
#define KEYBOARD_SET_LOWERCASE "\202"
|
||||
#define KEYBOARD_SET_LETTERS "\203"
|
||||
#define KEYBOARD_SET_NUMBERS "\204"
|
||||
|
||||
#define KEYBOARD_OFFSET_Y 15
|
||||
#define KEYBOARD_ROW_HEIGHT 40
|
||||
#define KEYBOARD_CHAR_WIDTH 30
|
||||
#define KEYBOARD_SPACE_WIDTH 135
|
||||
#define KEYBOARD_ENTER_WIDTH 80
|
||||
#define KEYBOARD_BITMAP_WIDTH 45
|
||||
|
||||
class TextKeyboard : public Keyboard
|
||||
{
|
||||
public:
|
||||
TextKeyboard();
|
||||
~TextKeyboard() override;
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override { return "TextKeyboard"; }
|
||||
#endif
|
||||
|
||||
static void show(FormField* field);
|
||||
|
||||
protected:
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void onEvent(event_t event) override;
|
||||
#endif
|
||||
|
||||
static TextKeyboard* _instance;
|
||||
};
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "layer.h"
|
||||
|
||||
std::list<Layer> Layer::stack;
|
||||
|
||||
Layer::Layer(Window* w, lv_group_t* g) : window(w), group(g) {}
|
||||
Layer::~Layer() { lv_group_del(group); }
|
||||
|
||||
static void _assign_lv_group(lv_group_t* g)
|
||||
{
|
||||
lv_group_set_default(g);
|
||||
|
||||
// associate it with all input devices
|
||||
lv_indev_t* indev = lv_indev_get_next(NULL);
|
||||
while (indev) {
|
||||
lv_indev_set_group(indev, g);
|
||||
indev = lv_indev_get_next(indev);
|
||||
}
|
||||
}
|
||||
|
||||
void Layer::push(Window* w)
|
||||
{
|
||||
// create a new group
|
||||
auto g = lv_group_create();
|
||||
_assign_lv_group(g);
|
||||
|
||||
// and store
|
||||
stack.emplace_back(w, g);
|
||||
}
|
||||
|
||||
void Layer::pop(Window* w)
|
||||
{
|
||||
if (stack.empty()) return;
|
||||
|
||||
if (back() == w) {
|
||||
stack.pop_back();
|
||||
} else {
|
||||
for (auto layer = stack.crbegin(); layer != stack.crend(); layer++) {
|
||||
if (layer->window == w) {
|
||||
stack.erase(layer.base());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!stack.empty()) {
|
||||
lv_group_t* g = stack.back().group;
|
||||
_assign_lv_group(g);
|
||||
} else {
|
||||
lv_group_set_default(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
Window* Layer::back()
|
||||
{
|
||||
if (stack.empty()) return nullptr;
|
||||
return stack.back().window;
|
||||
}
|
||||
|
||||
Window* Layer::getFirstOpaque()
|
||||
{
|
||||
for (auto layer = stack.crbegin(); layer != stack.crend(); layer++) {
|
||||
auto w = layer->window;
|
||||
if (w && (w->getWindowFlags() & OPAQUE)) return w;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "window.h"
|
||||
|
||||
class Layer
|
||||
{
|
||||
static std::list<Layer> stack;
|
||||
|
||||
Window* window;
|
||||
lv_group_t* group;
|
||||
|
||||
public:
|
||||
explicit Layer(Window* w, lv_group_t* g);
|
||||
~Layer();
|
||||
|
||||
static void push(Window* window);
|
||||
static void pop(Window* window);
|
||||
|
||||
static Window* back();
|
||||
static Window* getFirstOpaque();
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "libopenui_types.h"
|
||||
#include "libopenui_compat.h"
|
||||
|
||||
/* obsolete flags */
|
||||
#define BLINK 0
|
||||
#define TIMEHOUR 0
|
||||
|
||||
/* drawText flags */
|
||||
#define LEFT 0x00u /* align left */
|
||||
// 0x01u used by Lua in api_colorlcd.h
|
||||
#define VCENTERED 0x02u /* align center vertically */
|
||||
#define CENTERED 0x04u /* align center */
|
||||
#define RIGHT 0x08u /* align right */
|
||||
#define SHADOWED 0x80u /* black copy at +1 +1 */
|
||||
// 0x1000u used by Lua in api_colorlcd.h
|
||||
#define SPACING_NUMBERS_CONST 0x2000u
|
||||
// 0x8000u used by Lua in api_colorlcd.h
|
||||
|
||||
/* drawNumber flags */
|
||||
#define LEADING0 0x10u
|
||||
#define PREC1 0x20u
|
||||
#define PREC2 0x30u
|
||||
#define MODE(flags) ((((int8_t)(flags) & 0x30) - 0x10) >> 4)
|
||||
|
||||
/* telemetry flags */
|
||||
#define NO_UNIT 0x40u
|
||||
|
||||
#define FONT_MASK 0x0F00u
|
||||
#define FONT_INDEX(flags) (((flags) & FONT_MASK) >> 8u)
|
||||
#define FONT(xx) (unsigned(FONT_ ## xx ## _INDEX) << 8u)
|
||||
|
||||
#define ARGB_SPLIT(color, a, r, g, b) \
|
||||
uint16_t a = ((color) & 0xF000) >> 12; \
|
||||
uint16_t r = ((color) & 0x0F00) >> 8; \
|
||||
uint16_t g = ((color) & 0x00F0) >> 4; \
|
||||
uint16_t b = ((color) & 0x000F)
|
||||
|
||||
#define RGB_SPLIT(color, r, g, b) \
|
||||
uint16_t r = ((color) & 0xF800) >> 11; \
|
||||
uint16_t g = ((color) & 0x07E0) >> 5; \
|
||||
uint16_t b = ((color) & 0x001F)
|
||||
|
||||
#define ARGB_JOIN(a, r, g, b) \
|
||||
(((a&0xF) << 12) + ((r&0xF) << 8) + ((g&0xF) << 4) + (b&0xF))
|
||||
|
||||
#define RGB_JOIN(r, g, b) \
|
||||
(((r) << 11) + ((g) << 5) + (b))
|
||||
|
||||
#define GET_RED(color) \
|
||||
(((color) & 0xF800) >> 8)
|
||||
|
||||
#define GET_GREEN(color) \
|
||||
(((color) & 0x07E0) >> 3)
|
||||
|
||||
#define GET_BLUE(color) \
|
||||
(((color) & 0x001F) << 3)
|
||||
|
||||
#define OPACITY_MAX 0x0Fu
|
||||
#define OPACITY(value) ((value) & OPACITY_MAX)
|
||||
|
||||
#define RGB(r, g, b) (uint16_t)((((r) & 0xF8) << 8) + (((g) & 0xFC) << 3) + (((b) & 0xF8) >> 3))
|
||||
#define ARGB(a, r, g, b) (uint16_t)((((a) & 0xF0) << 8) + (((r) & 0xF0) << 4) + (((g) & 0xF0) << 0) + (((b) & 0xF0) >> 4))
|
||||
|
||||
#define COLOR2FLAGS(color) LcdFlags(unsigned(color) << 16u)
|
||||
#define COLOR_VAL(flags) ((flags) >> 16u)
|
||||
#define COLOR_MASK(flags) ((flags) & 0xFFFF0000u)
|
||||
|
||||
#define LV_OBJ_FLAG_ENCODER_ACCEL LV_OBJ_FLAG_USER_1
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "libopenui_config.h"
|
||||
|
||||
void lcdNextLayer();
|
||||
uint16_t* lcdGetScratchBuffer();
|
||||
void DMACopyBitmap(uint16_t * dest, uint16_t destw, uint16_t desth, uint16_t x, uint16_t y, const uint16_t * src, uint16_t srcw, uint16_t srch, uint16_t srcx, uint16_t srcy, uint16_t w, uint16_t h);
|
||||
void DMACopyAlphaBitmap(uint16_t * dest, uint16_t destw, uint16_t desth, uint16_t x, uint16_t y, const uint16_t * src, uint16_t srcw, uint16_t srch, uint16_t srcx, uint16_t srcy, uint16_t w, uint16_t h);
|
||||
void DMACopyAlphaMask(uint16_t * dest, uint16_t destw, uint16_t desth, uint16_t x, uint16_t y, const uint8_t * src, uint16_t srcw, uint16_t srch, uint16_t srcx, uint16_t srcy, uint16_t w, uint16_t h, uint16_t bg_color);
|
||||
void onKeyError();
|
||||
void killEvents(event_t event);
|
||||
|
||||
// multiplication factor between 0 and 25
|
||||
int8_t rotaryEncoderGetAccel();
|
||||
|
||||
//
|
||||
// These colors MUST be defined
|
||||
//
|
||||
|
||||
// #define COLOR_THEME_SECONDARY1
|
||||
// #define COLOR_THEME_SECONDARY3
|
||||
// #define COLOR_THEME_PRIMARY2
|
||||
// #define COLOR_THEME_FOCUS
|
||||
// #define COLOR_THEME_DISABLED
|
||||
// #define COLOR_THEME_ACTIVE
|
||||
// #define COLOR_THEME_FOCUS
|
||||
// #define COLOR_THEME_PRIMARY3
|
||||
// #define COLOR_THEME_SECONDARY1
|
||||
// #define COLOR_THEME_PRIMARY2
|
||||
// #define COLOR_THEME_SECONDARY1_THEME_SECONDARY1
|
||||
// #define COLOR_THEME_SECONDARY2
|
||||
// #define COLOR_THEME_PRIMARY2
|
||||
// #define COLOR_THEME_FOCUS
|
||||
// #define COLOR_THEME_PRIMARY1
|
||||
// #define COLOR_THEME_SECONDARY3
|
||||
// #define COLOR_THEME_FOCUS
|
||||
// #define CUSTOM_COLOR
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include "libopenui_file.h"
|
||||
#include "libopenui_defines.h"
|
||||
|
||||
const char * getFileExtension(const char * filename, uint8_t size, uint8_t extMaxLen, uint8_t * fnlen, uint8_t * extlen)
|
||||
{
|
||||
int len = size;
|
||||
if (!size) {
|
||||
len = strlen(filename);
|
||||
}
|
||||
if (!extMaxLen) {
|
||||
extMaxLen = LEN_FILE_EXTENSION_MAX;
|
||||
}
|
||||
if (fnlen != nullptr) {
|
||||
*fnlen = (uint8_t)len;
|
||||
}
|
||||
for (int i=len-1; i >= 0 && len-i <= extMaxLen; --i) {
|
||||
if (filename[i] == '.') {
|
||||
if (extlen) {
|
||||
*extlen = len-i;
|
||||
}
|
||||
return &filename[i];
|
||||
}
|
||||
}
|
||||
if (extlen != nullptr) {
|
||||
*extlen = 0;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
Check if given extension exists in a list of extensions.
|
||||
@param extension The extension to search for, including leading period.
|
||||
@param pattern One or more file extensions concatenated together, including the periods.
|
||||
The list is searched backwards and the first match, if any, is returned.
|
||||
eg: ".gif.jpg.jpeg.png"
|
||||
@param match Optional container to hold the matched file extension (wide enough to hold LEN_FILE_EXTENSION_MAX + 1).
|
||||
@retval true if a extension was found in the lost, false otherwise.
|
||||
*/
|
||||
bool isExtensionMatching(const char * extension, const char * pattern, char * match)
|
||||
{
|
||||
const char *ext;
|
||||
uint8_t extlen, fnlen;
|
||||
int plen;
|
||||
|
||||
ext = getFileExtension(pattern, 0, 0, &fnlen, &extlen);
|
||||
plen = (int)fnlen;
|
||||
while (plen > 0 && ext) {
|
||||
if (!strncasecmp(extension, ext, extlen)) {
|
||||
if (match != nullptr) strncat(&(match[0]='\0'), ext, extlen);
|
||||
return true;
|
||||
}
|
||||
plen -= extlen;
|
||||
if (plen > 0) {
|
||||
ext = getFileExtension(pattern, plen, 0, nullptr, &extlen);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// returns true if current working dir is at the root level
|
||||
bool isCwdAtRoot()
|
||||
{
|
||||
char path[10];
|
||||
if (f_getcwd(path, sizeof(path)-1) == FR_OK) {
|
||||
return (strcasecmp("/", path) == 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
Wrapper around the f_readdir() function which
|
||||
also returns ".." entry for sub-dirs. (FatFS 0.12 does
|
||||
not return ".", ".." dirs anymore)
|
||||
*/
|
||||
FRESULT sdReadDir(DIR * dir, FILINFO * fno, bool & firstTime)
|
||||
{
|
||||
FRESULT res;
|
||||
if (firstTime && !isCwdAtRoot()) {
|
||||
// fake parent directory entry
|
||||
strcpy(fno->fname, "..");
|
||||
fno->fattrib = AM_DIR;
|
||||
res = FR_OK;
|
||||
}
|
||||
else {
|
||||
res = f_readdir(dir, fno); /* Read a directory item */
|
||||
}
|
||||
firstTime = false;
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "libopenui_compat.h" // for strcasecmp / VC++
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <cinttypes>
|
||||
#include "ff.h"
|
||||
|
||||
constexpr uint8_t LEN_FILE_EXTENSION_MAX = 5; // longest used, including the dot, excluding null term.
|
||||
|
||||
const char * getFileExtension(const char * filename, uint8_t size = 0, uint8_t extMaxLen = 0, uint8_t * fnlen = nullptr, uint8_t * extlen = nullptr);
|
||||
bool isExtensionMatching(const char * extension, const char * pattern, char * match = nullptr);
|
||||
FRESULT sdReadDir(DIR * dir, FILINFO * fno, bool & firstTime);
|
||||
|
||||
// comparison, not case sensitive.
|
||||
inline bool compare_nocase(const std::string & first, const std::string & second)
|
||||
{
|
||||
return strcasecmp(first.c_str(), second.c_str()) < 0;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "libopenui_helpers.h"
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
#if defined(min)
|
||||
#undef min
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
template<class T>
|
||||
inline T min(T a, T b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline T max(T a, T b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline T limit(T vmin, T x, T vmax)
|
||||
{
|
||||
return ::min(::max(vmin, x), vmax);
|
||||
}
|
||||
|
||||
inline int divRoundClosest(int n, int d)
|
||||
{
|
||||
if (d == 0)
|
||||
return 0;
|
||||
else
|
||||
return ((n < 0) ^ (d < 0)) ? ((n - d/2)/d) : ((n + d/2)/d);
|
||||
}
|
||||
|
||||
inline int multDivRoundClosest(int v, int n, int d)
|
||||
{
|
||||
if (n == d)
|
||||
return v;
|
||||
else
|
||||
return divRoundClosest(v * n, d);
|
||||
}
|
||||
|
||||
inline int mod(int k, int n)
|
||||
{
|
||||
return ((k %= n) < 0) ? k + n : k;
|
||||
}
|
||||
|
||||
inline unsigned align32(unsigned n)
|
||||
{
|
||||
unsigned rest = (n & 3u);
|
||||
return rest ? n + 4u - rest : n;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline T sgn(T a)
|
||||
{
|
||||
return a > 0 ? 1 : (a < 0 ? -1 : 0);
|
||||
}
|
||||
|
||||
// TODO duplicated code
|
||||
inline std::string TEXT_AT_INDEX(const char *const *val, uint8_t idx)
|
||||
{
|
||||
return std::string(val[idx]);
|
||||
}
|
||||
|
||||
inline const char * findNextLine(const char * stack)
|
||||
{
|
||||
while (true) {
|
||||
const char * pos = strchr(stack, '\n');
|
||||
if (!pos)
|
||||
return nullptr;
|
||||
if (pos == stack || *((uint8_t *)(pos - 1)) < 0xFE)
|
||||
return pos;
|
||||
stack = pos + 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
typedef int coord_t;
|
||||
|
||||
struct point_t
|
||||
{
|
||||
coord_t x;
|
||||
coord_t y;
|
||||
|
||||
bool operator != (const point_t & b) const
|
||||
{
|
||||
return x != b.x || y != b.y;
|
||||
}
|
||||
};
|
||||
|
||||
struct rect_t
|
||||
{
|
||||
coord_t x, y, w, h;
|
||||
|
||||
constexpr coord_t left() const
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
constexpr coord_t right() const
|
||||
{
|
||||
return x + w;
|
||||
}
|
||||
|
||||
constexpr coord_t top() const
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
constexpr coord_t bottom() const
|
||||
{
|
||||
return y + h;
|
||||
}
|
||||
|
||||
bool contains(coord_t x, coord_t y) const
|
||||
{
|
||||
return (x >= this->x && x < this->x + this->w && y >= this->y && y < this->y + this->h);
|
||||
}
|
||||
|
||||
bool contains(const rect_t & other) const
|
||||
{
|
||||
return left() <= other.left() && right() >= other.right() && top() <= other.top() && bottom() >= other.bottom();
|
||||
}
|
||||
};
|
||||
|
||||
static const rect_t nullRect = {0, 0, 0, 0};
|
||||
|
||||
typedef uint32_t LcdFlags;
|
||||
typedef uint16_t event_t;
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "keyboard_base.h"
|
||||
|
||||
#include "lvgl/lvgl.h"
|
||||
|
||||
|
||||
|
||||
MainWindow * MainWindow::_instance = nullptr;
|
||||
|
||||
MainWindow::MainWindow() :
|
||||
Window(nullptr, {0, 0, LCD_W, LCD_H}, OPAQUE), invalidatedRect(rect)
|
||||
{
|
||||
}
|
||||
|
||||
void MainWindow::emptyTrash()
|
||||
{
|
||||
for (auto window : trash) {
|
||||
delete window;
|
||||
}
|
||||
trash.clear();
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::invalidate(const rect_t& rect)
|
||||
{
|
||||
if (invalidatedRect.w) {
|
||||
auto left = limit<coord_t>(0, rect.left(), invalidatedRect.left());
|
||||
auto right = limit<coord_t>(invalidatedRect.right(), rect.right(), LCD_W);
|
||||
auto top = limit<coord_t>(0, rect.top(), invalidatedRect.top());
|
||||
auto bottom =
|
||||
limit<coord_t>(rect.bottom(), invalidatedRect.bottom(), LCD_H);
|
||||
invalidatedRect = {left, top, right - left, bottom - top};
|
||||
} else {
|
||||
invalidatedRect = rect;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::run(bool trash)
|
||||
{
|
||||
auto start = ticksNow();
|
||||
|
||||
auto opaque = Layer::getFirstOpaque();
|
||||
if (opaque) opaque->checkEvents();
|
||||
|
||||
if (trash) emptyTrash();
|
||||
|
||||
auto delta = ticksNow() - start;
|
||||
if (delta > 10 * SYSTEM_TICKS_1MS) {
|
||||
TRACE_WINDOWS("MainWindow::run took %dms",
|
||||
(ticksNow() - start) / SYSTEM_TICKS_1MS);
|
||||
}
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include "layer.h"
|
||||
#include "bitmapbuffer.h"
|
||||
|
||||
class MainWindow: public Window
|
||||
{
|
||||
protected:
|
||||
// singleton
|
||||
MainWindow();
|
||||
|
||||
public:
|
||||
~MainWindow() override
|
||||
{
|
||||
children.clear();
|
||||
}
|
||||
|
||||
static bool isMainWindowCreated()
|
||||
{
|
||||
return _instance != nullptr;
|
||||
}
|
||||
|
||||
static MainWindow * instance()
|
||||
{
|
||||
if (!_instance)
|
||||
_instance = new MainWindow();
|
||||
|
||||
return _instance;
|
||||
}
|
||||
|
||||
#if defined(TESTS)
|
||||
static void create()
|
||||
{
|
||||
_instance = new MainWindow();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "MainWindow";
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void setActiveScreen() {
|
||||
lv_scr_load(lvobj);
|
||||
}
|
||||
|
||||
void invalidate()
|
||||
{
|
||||
invalidate({0, 0, rect.w, rect.h});
|
||||
}
|
||||
|
||||
void invalidate(const rect_t & rect) override;
|
||||
|
||||
bool needsRefresh() const
|
||||
{
|
||||
return invalidatedRect.w > 0;
|
||||
}
|
||||
|
||||
bool refresh();
|
||||
|
||||
void run(bool trash=true);
|
||||
|
||||
protected:
|
||||
static MainWindow * _instance;
|
||||
static void emptyTrash();
|
||||
rect_t invalidatedRect;
|
||||
const char * shutdown = nullptr;
|
||||
};
|
||||
+389
@@ -0,0 +1,389 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "menu.h"
|
||||
#include "font.h"
|
||||
#include "theme.h"
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
void MenuBody::onDrawBegin(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc)
|
||||
{
|
||||
lv_canvas_t* icon = (lv_canvas_t*)lines[row].getIcon();
|
||||
if (!icon) return;
|
||||
|
||||
lv_img_t* img = &icon->img;
|
||||
lv_coord_t cell_left = lv_obj_get_style_pad_left(lvobj, LV_PART_ITEMS);
|
||||
dsc->label_dsc->ofs_x = img->w + cell_left;
|
||||
}
|
||||
|
||||
void MenuBody::onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc)
|
||||
{
|
||||
if(row >= lines.size()) return;
|
||||
|
||||
lv_obj_t* icon = lines[row].getIcon();
|
||||
if (icon) {
|
||||
lv_draw_img_dsc_t img_dsc;
|
||||
lv_draw_img_dsc_init(&img_dsc);
|
||||
|
||||
lv_img_dsc_t* img = lv_canvas_get_img(icon);
|
||||
lv_area_t coords;
|
||||
|
||||
lv_coord_t area_h = lv_area_get_height(dsc->draw_area);
|
||||
|
||||
lv_coord_t cell_left = lv_obj_get_style_pad_left(lvobj, LV_PART_ITEMS);
|
||||
coords.x1 = dsc->draw_area->x1 + cell_left;
|
||||
coords.x2 = coords.x1 + img->header.w - 1;
|
||||
coords.y1 = dsc->draw_area->y1 + (area_h - img->header.h) / 2;
|
||||
coords.y2 = coords.y1 + img->header.h - 1;
|
||||
|
||||
lv_draw_img(dsc->draw_ctx, &img_dsc, &coords, img);
|
||||
}
|
||||
|
||||
if(lines[row].isChecked != nullptr &&
|
||||
lines[row].isChecked()) {
|
||||
lv_area_t coords;
|
||||
lv_coord_t area_h = lv_area_get_height(dsc->draw_area);
|
||||
lv_coord_t cell_right = lv_obj_get_style_pad_right(lvobj, LV_PART_ITEMS);
|
||||
lv_coord_t font_h = getFontHeight(FONT(STD));
|
||||
coords.x1 = dsc->draw_area->x2 - cell_right - font_h;
|
||||
coords.x2 = coords.x1 + font_h;
|
||||
coords.y1 = dsc->draw_area->y1 + (area_h - font_h) / 2;
|
||||
coords.y2 = coords.y1 + font_h - 1;
|
||||
lv_draw_label(dsc->draw_ctx, dsc->label_dsc, &coords, LV_SYMBOL_OK, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
static void _force_editing(lv_group_t* g)
|
||||
{
|
||||
lv_group_set_editing(g, true);
|
||||
}
|
||||
|
||||
MenuBody::MenuBody(Window * parent, const rect_t & rect):
|
||||
TableField(parent, rect)
|
||||
{
|
||||
// Allow encoder acceleration
|
||||
lv_obj_add_flag(lvobj, LV_OBJ_FLAG_ENCODER_ACCEL);
|
||||
// Add scroll bar if needed
|
||||
lv_obj_set_scrollbar_mode(lvobj, LV_SCROLLBAR_MODE_AUTO);
|
||||
|
||||
setColumnCount(1);
|
||||
setColumnWidth(0, rect.w);
|
||||
|
||||
lv_group_t* g = (lv_group_t*)lv_obj_get_group(lvobj);
|
||||
if (g) {
|
||||
setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
lv_group_set_focus_cb(g, _force_editing);
|
||||
} else {
|
||||
lv_group_set_focus_cb(g, nullptr);
|
||||
}
|
||||
});
|
||||
lv_group_set_editing(g, true);
|
||||
}
|
||||
}
|
||||
|
||||
void MenuBody::addLine(const std::string &text, std::function<void()> onPress,
|
||||
std::function<bool()> isChecked, bool update)
|
||||
{
|
||||
lines.emplace_back(text, std::move(onPress), std::move(isChecked), nullptr);
|
||||
|
||||
if (update) {
|
||||
auto idx = lines.size() - 1;
|
||||
lv_table_set_cell_value(lvobj, idx, 0, text.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void MenuBody::addLine(const uint8_t *icon_mask, const std::string &text,
|
||||
std::function<void()> onPress,
|
||||
std::function<bool()> isChecked,
|
||||
bool update)
|
||||
{
|
||||
lv_obj_t* canvas = lv_canvas_create(nullptr);
|
||||
lines.emplace_back(text, std::move(onPress), std::move(isChecked), canvas);
|
||||
|
||||
lv_coord_t w = *((uint16_t *)icon_mask);
|
||||
lv_coord_t h = *(((uint16_t *)icon_mask)+1);
|
||||
void* buf = (void*)(icon_mask + 4);
|
||||
lv_canvas_set_buffer(canvas, buf, w, h, LV_IMG_CF_ALPHA_8BIT);
|
||||
|
||||
if (update) {
|
||||
auto idx = lines.size() - 1;
|
||||
lv_table_set_cell_value(lvobj, idx, 0, text.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void MenuBody::updateLines()
|
||||
{
|
||||
setRowCount(lines.size());
|
||||
for(unsigned int idx = 0; idx < lines.size(); idx++) {
|
||||
lv_table_set_cell_value(lvobj, idx, 0, lines[idx].text.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void MenuBody::removeLines()
|
||||
{
|
||||
lines.clear();
|
||||
setRowCount(0);
|
||||
selectedIndex = 0;
|
||||
|
||||
// reset vertical scroll
|
||||
lv_obj_scroll_to_y(lvobj, 0, LV_ANIM_OFF);
|
||||
}
|
||||
|
||||
coord_t MenuBody::getContentHeight()
|
||||
{
|
||||
return lv_obj_get_self_height(lvobj);
|
||||
}
|
||||
|
||||
void MenuBody::onPress(size_t index)
|
||||
{
|
||||
Menu *menu = getParentMenu();
|
||||
if (index < lines.size()) {
|
||||
if (menu->multiple) {
|
||||
if (selectedIndex == (int)index)
|
||||
lines[index].onPress();
|
||||
else {
|
||||
setIndex(index);
|
||||
lines[index].onPress();
|
||||
}
|
||||
} else {
|
||||
// delete menu first to avoid
|
||||
// focus issues with onPress()
|
||||
menu->deleteLater();
|
||||
lines[index].onPress();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ensure index is in range and also handle wrapping index
|
||||
int MenuBody::rangeCheck(int index)
|
||||
{
|
||||
if (index < 0)
|
||||
index = lines.size() - 1;
|
||||
else if (index > (signed)lines.size() - 1)
|
||||
index = 0;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
void MenuBody::setIndex(int index)
|
||||
{
|
||||
if (index < (int)lines.size()) {
|
||||
if (index == selectedIndex) return;
|
||||
selectedIndex = index;
|
||||
|
||||
lv_obj_invalidate(lvobj);
|
||||
lv_table_t* table = (lv_table_t*)lvobj;
|
||||
|
||||
if (index < 0) {
|
||||
table->row_act = LV_TABLE_CELL_NONE;
|
||||
table->col_act = LV_TABLE_CELL_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
table->row_act = index;
|
||||
table->col_act = 0;
|
||||
|
||||
lv_coord_t h_before = 0;
|
||||
for (uint16_t i = 0; i < table->row_act; i++)
|
||||
h_before += table->row_h[i];
|
||||
|
||||
lv_coord_t row_h = table->row_h[table->row_act];
|
||||
lv_coord_t scroll_y = lv_obj_get_scroll_y(lvobj);
|
||||
|
||||
lv_obj_update_layout(lvobj);
|
||||
lv_coord_t h = lv_obj_get_height(lvobj);
|
||||
|
||||
lv_coord_t diff_y = 0;
|
||||
if (h_before < scroll_y) {
|
||||
diff_y = scroll_y - h_before;
|
||||
} else if (scroll_y + h < h_before + row_h) {
|
||||
diff_y = scroll_y + h - h_before - row_h;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
lv_obj_scroll_by_bounded(lvobj, 0, diff_y, LV_ANIM_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
void MenuBody::onPress(uint16_t row, uint16_t col)
|
||||
{
|
||||
onPress(row);
|
||||
}
|
||||
|
||||
void MenuBody::selectNext(MENU_DIRECTION direction)
|
||||
{
|
||||
// look for the next non separator line
|
||||
int index = selectedIndex + direction;
|
||||
setIndex(rangeCheck(index));
|
||||
}
|
||||
|
||||
|
||||
void MenuBody::onEvent(event_t event)
|
||||
{
|
||||
#if defined(HARDWARE_KEYS)
|
||||
if (event == EVT_KEY_BREAK(KEY_EXIT)) {
|
||||
onCancel();
|
||||
}
|
||||
else {
|
||||
TableField::onEvent(event);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void MenuBody::onCancel()
|
||||
{
|
||||
if(_onCancel) _onCancel();
|
||||
TableField::onCancel();
|
||||
}
|
||||
|
||||
MenuWindowContent::MenuWindowContent(Menu* parent) :
|
||||
ModalWindowContent(parent, {(LCD_W - MENUS_WIDTH) / 2,
|
||||
(LCD_H - MENUS_WIDTH) / 2, MENUS_WIDTH, 0}),
|
||||
body(this, {0, 0, width(), height()})
|
||||
{
|
||||
// body.setFocus(SET_FOCUS_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(lvobj, LV_OPA_100, LV_PART_MAIN);
|
||||
}
|
||||
|
||||
coord_t MenuWindowContent::getHeaderHeight() const
|
||||
{
|
||||
if (title) return lv_obj_get_height(title);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MenuWindowContent::deleteLater(bool detach, bool trash)
|
||||
{
|
||||
if (_deleted) return;
|
||||
body.deleteLater(true, false);
|
||||
ModalWindowContent::deleteLater(detach, trash);
|
||||
}
|
||||
|
||||
Menu::Menu(Window * parent, bool multiple):
|
||||
ModalWindow(parent, true),
|
||||
content(createMenuWindow(this)),
|
||||
multiple(multiple)
|
||||
{
|
||||
}
|
||||
|
||||
void Menu::setToolbar(Window * window)
|
||||
{
|
||||
toolbar = window;
|
||||
updatePosition();
|
||||
toolbar->setLeft(content->left() - toolbar->width());
|
||||
toolbar->setTop(content->top());
|
||||
toolbar->setHeight(content->height());
|
||||
}
|
||||
|
||||
void Menu::setOutline(Window* obj)
|
||||
{
|
||||
lv_obj_set_style_outline_width(obj->getLvObj(), 2, LV_PART_MAIN);
|
||||
lv_obj_set_style_outline_color(obj->getLvObj(), makeLvColor(COLOR_THEME_SECONDARY2), LV_PART_MAIN);
|
||||
lv_obj_set_style_outline_opa(obj->getLvObj(), LV_OPA_100, LV_PART_MAIN);
|
||||
lv_obj_set_style_outline_pad(obj->getLvObj(), 1, LV_PART_MAIN);
|
||||
|
||||
}
|
||||
|
||||
void Menu::updatePosition()
|
||||
{
|
||||
coord_t height = content->body.getContentHeight();
|
||||
|
||||
if (toolbar) {
|
||||
content->setLeft((LCD_W - content->width() + toolbar->width())/2);
|
||||
setOutline(toolbar);
|
||||
} else {
|
||||
content->setLeft((LCD_W - content->width())/2);
|
||||
auto headerHeight = content->getHeaderHeight();
|
||||
auto bodyHeight = min<coord_t>(height, MENUS_MAX_HEIGHT - headerHeight);
|
||||
content->setTop((LCD_H - headerHeight - bodyHeight) / 2);
|
||||
content->setHeight(headerHeight + bodyHeight);
|
||||
content->body.setTop(headerHeight);
|
||||
content->body.setHeight(bodyHeight);
|
||||
}
|
||||
setOutline(content);
|
||||
}
|
||||
|
||||
void Menu::setTitle(std::string text)
|
||||
{
|
||||
content->setTitle(std::move(text));
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
void Menu::addLine(const std::string &text, std::function<void()> onPress,
|
||||
std::function<bool()> isChecked)
|
||||
{
|
||||
content->body.addLine(text, std::move(onPress), std::move(isChecked));
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
void Menu::addLine(const uint8_t *icon_mask, const std::string &text,
|
||||
std::function<void()> onPress,
|
||||
std::function<bool()> isChecked)
|
||||
{
|
||||
content->body.addLine(icon_mask, text, std::move(onPress), std::move(isChecked));
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
void Menu::addLineBuffered(const std::string &text, std::function<void()> onPress,
|
||||
std::function<bool()> isChecked)
|
||||
{
|
||||
content->body.addLine(text, std::move(onPress), std::move(isChecked), false);
|
||||
}
|
||||
|
||||
void Menu::addLineBuffered(const uint8_t *icon_mask, const std::string &text,
|
||||
std::function<void()> onPress,
|
||||
std::function<bool()> isChecked)
|
||||
{
|
||||
content->body.addLine(icon_mask, text, std::move(onPress), std::move(isChecked), false);
|
||||
}
|
||||
|
||||
void Menu::updateLines()
|
||||
{
|
||||
content->body.updateLines();
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
void Menu::removeLines()
|
||||
{
|
||||
content->body.removeLines();
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
void Menu::onEvent(event_t event)
|
||||
{
|
||||
#if defined(HARDWARE_KEYS)
|
||||
if (toolbar &&
|
||||
(event == EVT_KEY_BREAK(KEY_PGDN) ||
|
||||
#if defined(KEYS_GPIO_REG_PGUP)
|
||||
event == EVT_KEY_BREAK(KEY_PGUP)
|
||||
#else
|
||||
event == EVT_KEY_LONG(KEY_PGDN)
|
||||
#endif
|
||||
)) {
|
||||
toolbar->onEvent(event);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Menu::onCancel()
|
||||
{
|
||||
deleteLater();
|
||||
}
|
||||
+245
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
|
||||
#include "modal_window.h"
|
||||
#include "table.h"
|
||||
|
||||
class Menu;
|
||||
class MenuWindowContent;
|
||||
|
||||
struct lvobj_delete {
|
||||
constexpr lvobj_delete() = default;
|
||||
void operator()(lv_obj_t* obj) const {
|
||||
lv_obj_del(obj);
|
||||
}
|
||||
};
|
||||
|
||||
class MenuBody: public TableField
|
||||
{
|
||||
friend class MenuWindowContent;
|
||||
friend class Menu;
|
||||
|
||||
enum MENU_DIRECTION
|
||||
{
|
||||
DIRECTION_UP = 1,
|
||||
DIRECTION_DOWN = -1
|
||||
};
|
||||
|
||||
class MenuLine
|
||||
{
|
||||
friend class MenuBody;
|
||||
|
||||
public:
|
||||
MenuLine(const std::string& text, std::function<void()> onPress, std::function<bool()> isChecked,
|
||||
lv_obj_t *icon) :
|
||||
text(text), onPress(std::move(onPress)), isChecked(std::move(isChecked)), icon(icon)
|
||||
{
|
||||
}
|
||||
|
||||
MenuLine(MenuLine &) = delete;
|
||||
MenuLine(MenuLine &&) = default;
|
||||
|
||||
lv_obj_t* getIcon() { return icon.get(); }
|
||||
|
||||
protected:
|
||||
std::string text;
|
||||
std::function<void()> onPress;
|
||||
std::function<bool()> isChecked;
|
||||
std::unique_ptr<lv_obj_t, lvobj_delete> icon;
|
||||
};
|
||||
|
||||
public:
|
||||
MenuBody(Window * parent, const rect_t & rect);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "MenuBody";
|
||||
}
|
||||
#endif
|
||||
|
||||
void setIndex(int index);
|
||||
|
||||
int selection() const
|
||||
{
|
||||
return selectedIndex;
|
||||
}
|
||||
|
||||
int count() const
|
||||
{
|
||||
return lines.size();
|
||||
}
|
||||
|
||||
void onEvent(event_t event) override;
|
||||
void onCancel() override;
|
||||
|
||||
void addLine(const std::string &text, std::function<void()> onPress,
|
||||
std::function<bool()> isChecked, bool update = true);
|
||||
|
||||
void addLine(const uint8_t *icon_mask, const std::string &text,
|
||||
std::function<void()> onPress,
|
||||
std::function<bool()> isChecked,
|
||||
bool update = true);
|
||||
|
||||
void updateLines();
|
||||
|
||||
void removeLines();
|
||||
|
||||
void setCancelHandler(std::function<void()> handler)
|
||||
{
|
||||
_onCancel = std::move(handler);
|
||||
}
|
||||
|
||||
coord_t getContentHeight();
|
||||
|
||||
void onPress(size_t index);
|
||||
|
||||
protected:
|
||||
void onPress(uint16_t row, uint16_t col) override;
|
||||
void onDrawBegin(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) override;
|
||||
void onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) override;
|
||||
|
||||
void selectNext(MENU_DIRECTION direction);
|
||||
int rangeCheck(int);
|
||||
|
||||
std::vector<MenuLine> lines;
|
||||
int selectedIndex = 0;
|
||||
std::function<void()> _onCancel;
|
||||
|
||||
inline Menu * getParentMenu();
|
||||
};
|
||||
|
||||
class MenuWindowContent: public ModalWindowContent
|
||||
{
|
||||
friend class Menu;
|
||||
|
||||
public:
|
||||
explicit MenuWindowContent(Menu * parent);
|
||||
|
||||
coord_t getHeaderHeight() const;
|
||||
|
||||
void deleteLater(bool detach = true, bool trash = true) override;
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "MenuWindowContent";
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
MenuBody body;
|
||||
};
|
||||
|
||||
class Menu: public ModalWindow
|
||||
{
|
||||
friend class MenuBody;
|
||||
|
||||
public:
|
||||
explicit Menu(Window * parent, bool multiple = false);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "Menu";
|
||||
}
|
||||
#endif
|
||||
|
||||
void setCancelHandler(std::function<void()> handler)
|
||||
{
|
||||
content->body.setCancelHandler(std::move(handler));
|
||||
}
|
||||
|
||||
void setWaitHandler(std::function<void()> handler)
|
||||
{
|
||||
waitHandler = std::move(handler);
|
||||
}
|
||||
|
||||
void setToolbar(Window* window);
|
||||
|
||||
void setTitle(std::string text);
|
||||
|
||||
void addLine(const std::string &text, std::function<void()> onPress,
|
||||
std::function<bool()> isChecked = nullptr);
|
||||
|
||||
void addLine(const uint8_t *icon_mask, const std::string &text,
|
||||
std::function<void()> onPress,
|
||||
std::function<bool()> isChecked = nullptr);
|
||||
|
||||
void addLineBuffered(const std::string &text, std::function<void()> onPress,
|
||||
std::function<bool()> isChecked = nullptr);
|
||||
|
||||
void addLineBuffered(const uint8_t *icon_mask, const std::string &text,
|
||||
std::function<void()> onPress,
|
||||
std::function<bool()> isChecked = nullptr);
|
||||
|
||||
void updateLines();
|
||||
|
||||
void addSeparator();
|
||||
|
||||
void removeLines();
|
||||
|
||||
unsigned count() const
|
||||
{
|
||||
return content->body.count();
|
||||
}
|
||||
|
||||
int selection() const
|
||||
{
|
||||
return content->body.selection();
|
||||
}
|
||||
|
||||
void select(int index)
|
||||
{
|
||||
content->body.setIndex(index);
|
||||
}
|
||||
|
||||
void onEvent(event_t event) override;
|
||||
void onCancel() override;
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
ModalWindow::checkEvents();
|
||||
if (waitHandler) {
|
||||
waitHandler();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
MenuWindowContent* content;
|
||||
bool multiple;
|
||||
Window * toolbar = nullptr;
|
||||
std::function<void()> waitHandler;
|
||||
void updatePosition();
|
||||
|
||||
void setOutline(Window* obj);
|
||||
};
|
||||
|
||||
Menu * MenuBody::getParentMenu()
|
||||
{
|
||||
return static_cast<Menu *>(getParent()->getParent());
|
||||
}
|
||||
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "menutoolbar.h"
|
||||
#include "choice.h"
|
||||
#include "font.h"
|
||||
|
||||
static void toolbar_btn_defocus(lv_event_t* event)
|
||||
{
|
||||
auto obj = lv_event_get_target(event);
|
||||
auto btn = (MenuToolbarButton*)lv_obj_get_user_data(obj);
|
||||
btn->check(false);
|
||||
}
|
||||
|
||||
MenuToolbarButton::MenuToolbarButton(Window* parent, const rect_t& rect,
|
||||
const char* picto) :
|
||||
Button(parent, rect, nullptr, 0, 0, window_create), picto(picto)
|
||||
{
|
||||
lv_obj_add_flag(lvobj, LV_OBJ_FLAG_CLICK_FOCUSABLE);
|
||||
lv_obj_add_flag(lvobj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
|
||||
|
||||
lv_obj_add_event_cb(lvobj, toolbar_btn_defocus, LV_EVENT_DEFOCUSED, nullptr);
|
||||
}
|
||||
|
||||
void MenuToolbarButton::paint(BitmapBuffer * dc)
|
||||
{
|
||||
lv_coord_t width = lv_obj_get_content_width(lvobj);
|
||||
if (checked()) {
|
||||
dc->drawSolidFilledRect(
|
||||
MENUS_TOOLBAR_BUTTON_PADDING, MENUS_TOOLBAR_BUTTON_PADDING,
|
||||
width - 2 * MENUS_TOOLBAR_BUTTON_PADDING,
|
||||
MENUS_TOOLBAR_BUTTON_WIDTH - 2 * MENUS_TOOLBAR_BUTTON_PADDING,
|
||||
COLOR_THEME_FOCUS);
|
||||
dc->drawText(width / 2, (rect.h - getFontHeight(FONT(L))) / 2 + 2,
|
||||
picto, FONT(L) | CENTERED | COLOR_THEME_PRIMARY2);
|
||||
} else {
|
||||
dc->drawText(width / 2, (rect.h - getFontHeight(FONT(L))) / 2 + 2,
|
||||
picto, FONT(L) | CENTERED | COLOR_THEME_PRIMARY1);
|
||||
}
|
||||
}
|
||||
|
||||
MenuToolbar::MenuToolbar(Choice* choice, Menu* menu) :
|
||||
Window(menu, MENUS_TOOLBAR_RECT, NO_SCROLLBAR),
|
||||
choice(choice),
|
||||
menu(menu),
|
||||
group(lv_group_create())
|
||||
{
|
||||
lv_obj_set_style_bg_opa(lvobj, LV_OPA_100, LV_PART_MAIN);
|
||||
lv_group_add_obj(group, lvobj);
|
||||
}
|
||||
|
||||
MenuToolbar::~MenuToolbar()
|
||||
{
|
||||
lv_group_del(group);
|
||||
}
|
||||
|
||||
void MenuToolbar::resetFilter()
|
||||
{
|
||||
if (lv_group_get_focused(group) != lvobj) {
|
||||
lv_group_focus_obj(lvobj);
|
||||
choice->fillMenu(menu);
|
||||
}
|
||||
}
|
||||
|
||||
void MenuToolbar::onEvent(event_t event)
|
||||
{
|
||||
|
||||
if (event == EVT_KEY_BREAK(KEY_PGDN)) {
|
||||
lv_group_focus_next(group);
|
||||
}
|
||||
#if defined(KEYS_GPIO_REG_PGUP)
|
||||
else if (event == EVT_KEY_BREAK(KEY_PGUP)) {
|
||||
#else
|
||||
else if (event == EVT_KEY_LONG(KEY_PGDN)) {
|
||||
killEvents(event);
|
||||
#endif
|
||||
lv_group_focus_prev(group);
|
||||
}
|
||||
|
||||
auto obj = lv_group_get_focused(group);
|
||||
if (!obj) {
|
||||
choice->fillMenu(menu);
|
||||
} else {
|
||||
lv_event_send(obj, LV_EVENT_CLICKED, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
rect_t MenuToolbar::getButtonRect(size_t buttons)
|
||||
{
|
||||
coord_t y = buttons * (MENUS_TOOLBAR_BUTTON_WIDTH + MENUS_TOOLBAR_BUTTON_PADDING);
|
||||
return {0, y, LV_PCT(100), MENUS_TOOLBAR_BUTTON_WIDTH};
|
||||
}
|
||||
|
||||
bool MenuToolbar::filterMenu(MenuToolbarButton* btn, int16_t filtermin,
|
||||
int16_t filtermax)
|
||||
{
|
||||
btn->check(!btn->checked());
|
||||
|
||||
Choice::FilterFct filter = nullptr;
|
||||
if (btn->checked()) {
|
||||
filter = [=](int16_t index) {
|
||||
return index >= filtermin && index <= filtermax;
|
||||
};
|
||||
}
|
||||
|
||||
choice->fillMenu(menu, filter);
|
||||
return btn->checked();
|
||||
}
|
||||
|
||||
typedef std::function<bool(int)> IsValueAvailable;
|
||||
static int getFirstAvailable(int min, int max, IsValueAvailable isValueAvailable)
|
||||
{
|
||||
int retval = 0;
|
||||
for (int i = min; i <= max; i++) {
|
||||
if (isValueAvailable(i)) {
|
||||
retval = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void MenuToolbar::addButton(const char* picto, int16_t filtermin,
|
||||
int16_t filtermax)
|
||||
{
|
||||
int vmin = choice->vmin;
|
||||
int vmax = choice->vmax;
|
||||
|
||||
if (vmin > filtermin || vmax < filtermin) return;
|
||||
|
||||
if (choice->isValueAvailable &&
|
||||
getFirstAvailable(filtermin, filtermax, choice->isValueAvailable) == 0)
|
||||
return;
|
||||
|
||||
rect_t r = getButtonRect(children.size());
|
||||
auto button = new MenuToolbarButton(this, r, picto);
|
||||
|
||||
button->setPressHandler(
|
||||
std::bind(&MenuToolbar::filterMenu, this, button, filtermin, filtermax));
|
||||
|
||||
lv_group_add_obj(group, button->getLvObj());
|
||||
}
|
||||
|
||||
void MenuToolbar::onClicked()
|
||||
{
|
||||
choice->fillMenu(menu);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "button.h"
|
||||
#include "menu.h"
|
||||
|
||||
class Choice;
|
||||
|
||||
class MenuToolbarButton : public Button
|
||||
{
|
||||
public:
|
||||
MenuToolbarButton(Window* parent, const rect_t& rect, const char* picto);
|
||||
void paint(BitmapBuffer* dc) override;
|
||||
|
||||
protected:
|
||||
const char* picto;
|
||||
};
|
||||
|
||||
class MenuToolbar : public Window
|
||||
{
|
||||
// friend Menu;
|
||||
|
||||
public:
|
||||
MenuToolbar(Choice* choice, Menu* menu);
|
||||
~MenuToolbar();
|
||||
|
||||
void resetFilter();
|
||||
void onEvent(event_t event) override;
|
||||
|
||||
protected:
|
||||
Choice* choice;
|
||||
Menu* menu;
|
||||
|
||||
lv_group_t* group;
|
||||
|
||||
void addButton(const char* picto, int16_t filtermin, int16_t filtermax);
|
||||
bool filterMenu(MenuToolbarButton* btn, int16_t filtermin, int16_t filtermax);
|
||||
|
||||
rect_t getButtonRect(size_t buttons);
|
||||
|
||||
void onClicked() override;
|
||||
};
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
|
||||
#include "modal_window.h"
|
||||
#include "keyboard_base.h"
|
||||
#include "font.h"
|
||||
#include "layer.h"
|
||||
|
||||
ModalWindow::ModalWindow(Window * parent, bool closeWhenClickOutside):
|
||||
Window(parent->getFullScreenWindow(), {0, 0, LCD_W, LCD_H}),
|
||||
closeWhenClickOutside(closeWhenClickOutside)
|
||||
{
|
||||
Layer::push(this);
|
||||
lv_obj_set_style_bg_color(lvobj, lv_color_black(), LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_opa(lvobj, LV_OPA_50, LV_PART_MAIN);
|
||||
}
|
||||
|
||||
void ModalWindow::deleteLater(bool detach, bool trash)
|
||||
{
|
||||
if (_deleted) return;
|
||||
Layer::pop(this);
|
||||
Window::deleteLater(detach, trash);
|
||||
}
|
||||
|
||||
void ModalWindow::onClicked()
|
||||
{
|
||||
if (closeWhenClickOutside) {
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
ModalWindowContent::ModalWindowContent(ModalWindow* parent,
|
||||
const rect_t& rect) :
|
||||
Window(parent, rect, OPAQUE)
|
||||
{
|
||||
}
|
||||
|
||||
void ModalWindowContent::onClicked()
|
||||
{
|
||||
Keyboard::hide();
|
||||
}
|
||||
|
||||
void ModalWindowContent::setTitle(const std::string& text)
|
||||
{
|
||||
if (!title) {
|
||||
title = lv_label_create(lvobj);
|
||||
lv_obj_move_to_index(title, 0);
|
||||
lv_obj_set_width(title, lv_pct(100));
|
||||
lv_obj_set_style_pad_all(title, PAGE_PADDING, LV_PART_MAIN);
|
||||
|
||||
lv_color_t bg_color = makeLvColor(COLOR_THEME_SECONDARY1);
|
||||
lv_obj_set_style_bg_color(title, bg_color, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_opa(title, LV_OPA_100, LV_PART_MAIN);
|
||||
|
||||
lv_color_t txt_color = makeLvColor(COLOR_THEME_PRIMARY2);
|
||||
lv_obj_set_style_text_color(title, txt_color, LV_PART_MAIN);
|
||||
|
||||
lv_obj_update_layout(lvobj);
|
||||
}
|
||||
lv_label_set_text(title, text.c_str());
|
||||
}
|
||||
|
||||
std::string ModalWindowContent::getTitle() const
|
||||
{
|
||||
if (!title) return std::string();
|
||||
return lv_label_get_text(title);
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "window.h"
|
||||
|
||||
class ModalWindow : public Window
|
||||
{
|
||||
public:
|
||||
explicit ModalWindow(Window* parent, bool closeWhenClickOutside = false);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override { return "ModalWindow"; }
|
||||
#endif
|
||||
|
||||
void setCloseWhenClickOutside(bool value = true)
|
||||
{
|
||||
closeWhenClickOutside = value;
|
||||
}
|
||||
|
||||
void onClicked() override;
|
||||
void deleteLater(bool detach = true, bool trash = true) override;
|
||||
|
||||
protected:
|
||||
bool closeWhenClickOutside;
|
||||
};
|
||||
|
||||
class ModalWindowContent : public Window
|
||||
{
|
||||
public:
|
||||
explicit ModalWindowContent(ModalWindow* parent, const rect_t& rect);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override { return "ModalWindowContent"; }
|
||||
#endif
|
||||
|
||||
virtual void setTitle(const std::string& text);
|
||||
std::string getTitle() const;
|
||||
|
||||
void onClicked() override;
|
||||
|
||||
protected:
|
||||
lv_obj_t* title = nullptr;
|
||||
};
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "numberedit.h"
|
||||
#include "widgets/field_edit.h"
|
||||
#include "keyboard_number.h"
|
||||
|
||||
static void numberedit_cb(lv_event_t* e)
|
||||
{
|
||||
NumberEdit* numEdit = (NumberEdit*)lv_event_get_user_data(e);
|
||||
if (!numEdit || numEdit->deleted()) return;
|
||||
|
||||
uint32_t key = lv_event_get_key(e);
|
||||
switch (key) {
|
||||
case LV_KEY_LEFT:
|
||||
numEdit->onEvent(EVT_ROTARY_LEFT);
|
||||
break;
|
||||
case LV_KEY_RIGHT:
|
||||
numEdit->onEvent(EVT_ROTARY_RIGHT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NumberEdit::NumberEdit(Window* parent, const rect_t& rect, int vmin, int vmax,
|
||||
std::function<int()> getValue,
|
||||
std::function<void(int)> setValue,
|
||||
WindowFlags windowFlags, LcdFlags textFlags) :
|
||||
BaseNumberEdit(parent, rect, vmin, vmax, std::move(getValue),
|
||||
std::move(setValue), windowFlags, textFlags,
|
||||
field_edit_create)
|
||||
{
|
||||
// Allow encoder acceleration
|
||||
lv_obj_add_flag(lvobj, LV_OBJ_FLAG_ENCODER_ACCEL);
|
||||
|
||||
// properties
|
||||
lv_obj_set_scrollbar_mode(lvobj, LV_SCROLLBAR_MODE_OFF);
|
||||
lv_textarea_set_password_mode(lvobj, false);
|
||||
lv_textarea_set_one_line(lvobj, true);
|
||||
lv_obj_add_event_cb(lvobj, numberedit_cb, LV_EVENT_KEY, this);
|
||||
|
||||
setHeight(33);
|
||||
padTop(5);
|
||||
padRight(4);
|
||||
lv_obj_set_style_text_align(lvobj, LV_TEXT_ALIGN_RIGHT, 0);
|
||||
lv_obj_set_style_radius(lvobj, 4, 0);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void NumberEdit::onEvent(event_t event)
|
||||
{
|
||||
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
|
||||
|
||||
if (editMode) {
|
||||
switch (event) {
|
||||
#if defined(HARDWARE_KEYS)
|
||||
case EVT_ROTARY_RIGHT: {
|
||||
int value = getValue();
|
||||
auto step = getStep();
|
||||
step += (rotaryEncoderGetAccel() * getAccelFactor()) / 8;
|
||||
do {
|
||||
value += step;
|
||||
} while (isValueAvailable && !isValueAvailable(value) && value <= vmax);
|
||||
if (value <= vmax) {
|
||||
setValue(value);
|
||||
}
|
||||
else {
|
||||
setValue(vmax);
|
||||
onKeyError();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
case EVT_ROTARY_LEFT: {
|
||||
int value = getValue();
|
||||
auto step = getStep();
|
||||
step += (rotaryEncoderGetAccel() * getAccelFactor()) / 8;
|
||||
do {
|
||||
value -= step;
|
||||
} while (isValueAvailable && !isValueAvailable(value) && value >= vmin);
|
||||
if (value >= vmin) {
|
||||
setValue(value);
|
||||
}
|
||||
else {
|
||||
setValue(vmin);
|
||||
onKeyError();
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
case EVT_VIRTUAL_KEY_PLUS:
|
||||
setValue(getValue() + getStep());
|
||||
break;
|
||||
|
||||
case EVT_VIRTUAL_KEY_MINUS:
|
||||
setValue(getValue() - getStep());
|
||||
break;
|
||||
|
||||
case EVT_VIRTUAL_KEY_FORWARD:
|
||||
setValue(getValue() + getFastStep() * getStep());
|
||||
break;
|
||||
|
||||
case EVT_VIRTUAL_KEY_BACKWARD:
|
||||
setValue(getValue() - getFastStep() * getStep());
|
||||
break;
|
||||
|
||||
case EVT_VIRTUAL_KEY_DEFAULT:
|
||||
setValue(getDefault());
|
||||
break;
|
||||
|
||||
case EVT_VIRTUAL_KEY_MAX:
|
||||
setValue(getMax());
|
||||
break;
|
||||
|
||||
case EVT_VIRTUAL_KEY_MIN:
|
||||
setValue(getMin());
|
||||
break;
|
||||
|
||||
case EVT_VIRTUAL_KEY_SIGN:
|
||||
setValue(-getValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FormField::onEvent(event);
|
||||
}
|
||||
|
||||
void NumberEdit::onClicked()
|
||||
{
|
||||
lv_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act());
|
||||
if(indev_type == LV_INDEV_TYPE_POINTER) {
|
||||
NumberKeyboard::show(this);
|
||||
return;
|
||||
}
|
||||
|
||||
FormField::onClicked();
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "basenumberedit.h"
|
||||
#include <string>
|
||||
|
||||
class NumberEdit : public BaseNumberEdit
|
||||
{
|
||||
public:
|
||||
NumberEdit(Window* parent, const rect_t& rect, int vmin, int vmax,
|
||||
std::function<int()> getValue,
|
||||
std::function<void(int)> setValue = nullptr,
|
||||
WindowFlags windowFlags = 0, LcdFlags textFlags = 0);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "NumberEdit(" + std::to_string(getValue()) + ")";
|
||||
}
|
||||
#endif
|
||||
|
||||
void setAvailableHandler(std::function<bool(int)> handler)
|
||||
{
|
||||
isValueAvailable = std::move(handler);
|
||||
}
|
||||
|
||||
void onEvent(event_t event) override;
|
||||
void onClicked() override;
|
||||
|
||||
protected:
|
||||
std::function<bool(int)> isValueAvailable;
|
||||
};
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "progress.h"
|
||||
#include "theme.h"
|
||||
|
||||
void Progress::paint(BitmapBuffer * dc)
|
||||
{
|
||||
auto val = value > 100 ? 100 : value;
|
||||
theme->drawProgressBar(dc, 0, 0, width(), height(), val, 100);
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "window.h"
|
||||
|
||||
class Progress: public Window {
|
||||
public:
|
||||
Progress(Window * parent, const rect_t & rect):
|
||||
Window(parent, rect)
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "Progress";
|
||||
}
|
||||
#endif
|
||||
|
||||
void setValue(int newValue)
|
||||
{
|
||||
if (newValue != value) {
|
||||
value = newValue;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void paint(BitmapBuffer * dc) override;
|
||||
|
||||
protected:
|
||||
int value = 0;
|
||||
};
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <touch.h>
|
||||
#include <choice.h>
|
||||
#include <font.h>
|
||||
#include <static.h>
|
||||
#include <limits.h>
|
||||
#include "libopenui_config.h"
|
||||
|
||||
constexpr WindowFlags ROLLER_SEPARATION_LINES = (FORM_FLAGS_LAST << 1u);
|
||||
constexpr coord_t SCROLL_POSITION_INVALIDATED = INT_MIN;
|
||||
|
||||
class Roller: public Choice
|
||||
{
|
||||
public:
|
||||
Roller(FormGroup * parent, const rect_t & rect, const char * label, const char * const * values, int vmin, int vmax, std::function<int()> getValue, std::function<void(int)> setValue = nullptr, WindowFlags windowFlags = ROLLER_SEPARATION_LINES):
|
||||
Choice(parent, rect, values, vmin, vmax, std::move(getValue), std::move(setValue), windowFlags | NO_SCROLLBAR)
|
||||
{
|
||||
init(label);
|
||||
}
|
||||
|
||||
Roller(FormGroup * parent, const rect_t & rect, const char * label, std::vector<std::string> values, int vmin, int vmax, std::function<int()> getValue, std::function<void(int)> setValue = nullptr, WindowFlags windowFlags = ROLLER_SEPARATION_LINES):
|
||||
Choice(parent, rect, std::move(values), vmin, vmax, std::move(getValue), std::move(setValue), windowFlags | NO_SCROLLBAR)
|
||||
{
|
||||
init(label);
|
||||
}
|
||||
|
||||
void init(const char * label)
|
||||
{
|
||||
if (label) {
|
||||
// the label is another window, could be changed, but is it needed?
|
||||
new StaticText(parent, {rect.x, rect.y - ROLLER_LINE_HEIGHT, rect.w, ROLLER_LINE_HEIGHT}, label, 0, CENTERED);
|
||||
}
|
||||
|
||||
setHeight(ROLLER_LINE_HEIGHT * 3 - 1);
|
||||
setPageHeight(ROLLER_LINE_HEIGHT);
|
||||
setInnerHeight(INFINITE_HEIGHT);
|
||||
updateScrollPositionFromValue();
|
||||
}
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "Roller";
|
||||
}
|
||||
#endif
|
||||
|
||||
void paint(BitmapBuffer * dc) override
|
||||
{
|
||||
int32_t value = getValue();
|
||||
auto valuesCount = (int)getValuesCount();
|
||||
if (valuesCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int index = (scrollPositionY - ROLLER_LINE_HEIGHT + 1) / ROLLER_LINE_HEIGHT;
|
||||
coord_t y = index * ROLLER_LINE_HEIGHT;
|
||||
coord_t yMax = scrollPositionY + 3 * ROLLER_LINE_HEIGHT;
|
||||
index = mod(index, valuesCount);
|
||||
|
||||
while (y < yMax) {
|
||||
auto displayedValue = getValueFromIndex(index);
|
||||
|
||||
auto fgColor = COLOR_THEME_DISABLED;
|
||||
if (value == displayedValue) {
|
||||
fgColor = COLOR_THEME_PRIMARY2 | FONT(STD);
|
||||
}
|
||||
|
||||
unsigned valueIndex = displayedValue - vmin;
|
||||
if (valueIndex < values.size()) {
|
||||
dc->drawText(width() / 2, y, values[valueIndex].c_str(), fgColor | CENTERED);
|
||||
}
|
||||
else {
|
||||
dc->drawNumber(width() / 2, y, displayedValue, fgColor | CENTERED);
|
||||
}
|
||||
|
||||
if (windowFlags & ROLLER_SEPARATION_LINES) {
|
||||
dc->drawSolidHorizontalLine(0, y - 10, width(), COLOR_THEME_DISABLED);
|
||||
}
|
||||
|
||||
if (++index == valuesCount)
|
||||
index = 0;
|
||||
|
||||
y += ROLLER_LINE_HEIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
Window::checkEvents();
|
||||
|
||||
if (lastEditMode != editMode) {
|
||||
updateScrollPositionFromValue();
|
||||
lastEditMode = editMode;
|
||||
}
|
||||
|
||||
if (lastScrollPositionY == SCROLL_POSITION_INVALIDATED) {
|
||||
updateScrollPositionFromValue();
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
if (touchState.event != TE_SLIDE) {
|
||||
if (scrollPositionY != lastScrollPositionY) {
|
||||
updateValueFromScrollPosition();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// virtual not needed until now
|
||||
void setMin(int value)
|
||||
{
|
||||
Choice::setMin(value);
|
||||
invalidateScrollPosition();
|
||||
}
|
||||
|
||||
// virtual not needed until now
|
||||
void setMax(int value)
|
||||
{
|
||||
Choice::setMax(value);
|
||||
invalidateScrollPosition();
|
||||
}
|
||||
|
||||
// virtual not needed until now
|
||||
void setAvailableHandler(std::function<bool(int)> handler)
|
||||
{
|
||||
Choice::setAvailableHandler(std::move(handler));
|
||||
invalidateScrollPosition();
|
||||
}
|
||||
|
||||
void invalidateScrollPosition()
|
||||
{
|
||||
lastScrollPositionY = SCROLL_POSITION_INVALIDATED;
|
||||
}
|
||||
|
||||
protected:
|
||||
coord_t lastScrollPositionY = SCROLL_POSITION_INVALIDATED;
|
||||
bool lastEditMode = false;
|
||||
|
||||
void updateScrollPositionFromValue()
|
||||
{
|
||||
setScrollPositionY(ROLLER_LINE_HEIGHT * (getIndexFromValue(this->getValue()) - 1));
|
||||
lastScrollPositionY = scrollPositionY;
|
||||
}
|
||||
|
||||
void updateValueFromScrollPosition()
|
||||
{
|
||||
lastScrollPositionY = scrollPositionY;
|
||||
|
||||
auto valuesCount = getValuesCount();
|
||||
auto newValue = getValueFromIndex(mod((scrollPositionY / ROLLER_LINE_HEIGHT) + 1, valuesCount));
|
||||
|
||||
setValue(newValue);
|
||||
invalidate();
|
||||
}
|
||||
};
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "slider.h"
|
||||
#include "theme.h"
|
||||
|
||||
#include "LvglWrapper.h"
|
||||
|
||||
static void slider_changed_cb(lv_event_t* e)
|
||||
{
|
||||
lv_obj_t* target = lv_event_get_target(e);
|
||||
auto code = lv_event_get_code(e);
|
||||
|
||||
Slider* sl = (Slider*)lv_obj_get_user_data(target);
|
||||
if (code == LV_EVENT_VALUE_CHANGED) {
|
||||
if (sl != nullptr) sl->setValue(lv_slider_get_value(target));
|
||||
}
|
||||
}
|
||||
|
||||
static lv_style_t style_main;
|
||||
static lv_style_t style_ind;
|
||||
static lv_style_t style_knob;
|
||||
static lv_style_t style_focused;
|
||||
static lv_style_t style_edit;
|
||||
|
||||
constexpr coord_t SLIDER_PADDING = 6;
|
||||
|
||||
Slider::Slider(Window* parent, const rect_t& rect, int32_t vmin, int32_t vmax,
|
||||
std::function<int()> getValue,
|
||||
std::function<void(int)> setValue) :
|
||||
FormField(parent,
|
||||
{rect.x + SLIDER_PADDING, rect.y + SLIDER_PADDING,
|
||||
rect.w - 2 * SLIDER_PADDING, rect.h - 2 * SLIDER_PADDING},
|
||||
0, 0, lv_slider_create),
|
||||
vmin(vmin),
|
||||
vmax(vmax),
|
||||
_getValue(std::move(getValue)),
|
||||
_setValue(std::move(setValue))
|
||||
{
|
||||
lv_obj_add_event_cb(lvobj, slider_changed_cb, LV_EVENT_VALUE_CHANGED, this);
|
||||
lv_obj_add_event_cb(lvobj, slider_changed_cb, LV_EVENT_PRESSED, this);
|
||||
lv_slider_set_range(lvobj, vmin, vmax);
|
||||
|
||||
if (_getValue != nullptr)
|
||||
lv_slider_set_value(lvobj, _getValue(), LV_ANIM_OFF);
|
||||
|
||||
// LV_PART_MAIN
|
||||
lv_style_init(&style_main);
|
||||
lv_style_set_bg_opa(&style_main, LV_OPA_100);
|
||||
lv_style_set_bg_color(&style_main, makeLvColor(COLOR_THEME_SECONDARY1));
|
||||
lv_style_set_radius(&style_main, LV_RADIUS_CIRCLE);
|
||||
lv_obj_add_style(lvobj, &style_main, LV_PART_MAIN);
|
||||
|
||||
// LV_PART_INDICATOR
|
||||
lv_style_init(&style_ind);
|
||||
lv_style_set_bg_opa(&style_ind, LV_OPA_100);
|
||||
lv_style_set_bg_color(&style_ind, makeLvColor(COLOR_THEME_SECONDARY1));
|
||||
lv_obj_add_style(lvobj, &style_ind, LV_PART_INDICATOR);
|
||||
|
||||
// Knob
|
||||
lv_style_init(&style_knob);
|
||||
lv_style_set_bg_color(&style_knob, makeLvColor(COLOR_THEME_PRIMARY2));
|
||||
lv_style_set_border_color(&style_knob, makeLvColor(COLOR_THEME_SECONDARY1));
|
||||
lv_style_set_border_width(&style_knob, 2);
|
||||
lv_obj_add_style(lvobj, &style_knob, LV_PART_KNOB);
|
||||
|
||||
// LV_STATE_FOCUSED
|
||||
lv_style_init(&style_focused);
|
||||
lv_style_set_bg_color(&style_focused, makeLvColor(COLOR_THEME_FOCUS));
|
||||
lv_style_set_outline_width(&style_focused, 0);
|
||||
|
||||
lv_obj_add_style(lvobj, &style_focused, LV_PART_MAIN | LV_STATE_FOCUSED);
|
||||
lv_obj_add_style(lvobj, &style_focused, LV_PART_MAIN | LV_STATE_FOCUSED | LV_STATE_EDITED);
|
||||
lv_obj_add_style(lvobj, &style_focused, LV_PART_INDICATOR | LV_STATE_FOCUSED);
|
||||
lv_obj_add_style(lvobj, &style_focused, LV_PART_INDICATOR | LV_STATE_FOCUSED | LV_STATE_EDITED);
|
||||
|
||||
lv_style_init(&style_edit);
|
||||
lv_style_set_bg_color(&style_edit, makeLvColor(COLOR_THEME_EDIT));
|
||||
lv_obj_add_style(lvobj, &style_edit, LV_PART_KNOB | LV_STATE_FOCUSED | LV_STATE_EDITED);
|
||||
}
|
||||
|
||||
|
||||
int Slider::value(coord_t x) const
|
||||
{
|
||||
return vmin + ((vmax - vmin) * x + (rect.w / 2)) / rect.w;
|
||||
}
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "form.h"
|
||||
|
||||
class Slider : public FormField
|
||||
{
|
||||
public:
|
||||
Slider(Window* parent, const rect_t& rect, int32_t vmin, int32_t vmax,
|
||||
std::function<int()> getValue, std::function<void(int)> setValue);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override { return "Slider"; }
|
||||
#endif
|
||||
|
||||
void setValue(int value)
|
||||
{
|
||||
if (_setValue != nullptr) _setValue(limit(vmin, value, vmax));
|
||||
}
|
||||
|
||||
protected:
|
||||
int vmin;
|
||||
int vmax;
|
||||
std::function<int()> _getValue;
|
||||
std::function<void(int)> _setValue;
|
||||
|
||||
int value(coord_t x) const;
|
||||
};
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "static.h"
|
||||
#include "font.h"
|
||||
|
||||
StaticText::StaticText(Window* parent, const rect_t& rect, std::string txt,
|
||||
WindowFlags windowFlags, LcdFlags textFlags) :
|
||||
Window(parent, rect, windowFlags, textFlags, lv_label_create),
|
||||
text(std::move(txt))
|
||||
{
|
||||
lv_obj_enable_style_refresh(false);
|
||||
lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICK_FOCUSABLE);
|
||||
|
||||
lv_obj_set_style_text_font(lvobj, getFont(textFlags), LV_PART_MAIN);
|
||||
lv_obj_set_style_text_color(lvobj, makeLvColor(textFlags), LV_PART_MAIN);
|
||||
|
||||
if (textFlags & CENTERED)
|
||||
lv_obj_set_style_text_align(lvobj, LV_TEXT_ALIGN_CENTER, 0);
|
||||
else if (textFlags & RIGHT)
|
||||
lv_obj_set_style_text_align(lvobj, LV_TEXT_ALIGN_RIGHT, 0);
|
||||
|
||||
if (windowFlags & BUTTON_BACKGROUND) {
|
||||
lv_obj_set_style_bg_opa(lvobj, LV_OPA_100, LV_PART_MAIN);
|
||||
setBackgroundColor(COLOR_THEME_SECONDARY2);
|
||||
}
|
||||
|
||||
lv_obj_set_style_grid_cell_x_align(lvobj, LV_GRID_ALIGN_STRETCH, 0);
|
||||
lv_label_set_text(lvobj, text.c_str());
|
||||
lv_obj_set_height(lvobj, LV_SIZE_CONTENT);
|
||||
lv_obj_enable_style_refresh(true);
|
||||
lv_obj_refresh_style(lvobj, LV_PART_ANY, LV_STYLE_PROP_ANY);
|
||||
}
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string StaticText::getName() const
|
||||
{
|
||||
return "StaticText \"" + text + "\"";
|
||||
}
|
||||
#endif
|
||||
|
||||
void StaticText::setText(std::string value)
|
||||
{
|
||||
if (text != value) {
|
||||
text = std::move(value);
|
||||
if (lvobj) lv_label_set_text(lvobj, text.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& StaticText::getText() const
|
||||
{
|
||||
return text;
|
||||
}
|
||||
|
||||
void StaticText::setBackgroundColor(LcdFlags color)
|
||||
{
|
||||
bgColor = color;
|
||||
|
||||
if (!lvobj) return;
|
||||
|
||||
lv_color_t c = makeLvColor(bgColor);
|
||||
lv_obj_set_style_bg_color(lvobj, c, LV_PART_MAIN);
|
||||
}
|
||||
|
||||
void StaticText::setBackgroudOpacity(uint32_t opa)
|
||||
{
|
||||
lv_obj_set_style_bg_opa(lvobj, opa, LV_PART_MAIN);
|
||||
}
|
||||
|
||||
void StaticText::setFont(LcdFlags font)
|
||||
{
|
||||
lv_obj_set_style_text_font(lvobj, getFont(font), 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
void DynamicNumber<uint32_t>::updateText()
|
||||
{
|
||||
if (lvobj) {
|
||||
const char* p = prefix ? prefix : "";
|
||||
const char* s = suffix ? suffix : "";
|
||||
if ((textFlags & PREC2) == PREC2) {
|
||||
lv_label_set_text_fmt(lvobj, "%s%" PRIu32 ".%02" PRIu32 "%s", p,
|
||||
value / 100, value % 100, s);
|
||||
} else if (textFlags & PREC1) {
|
||||
lv_label_set_text_fmt(lvobj, "%s%" PRIu32 ".%01" PRIu32 "%s", p,
|
||||
value / 10, value % 10, s);
|
||||
} else {
|
||||
lv_label_set_text_fmt(lvobj, "%s%" PRIu32 "%s", p, value, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void DynamicNumber<int32_t>::updateText()
|
||||
{
|
||||
if (lvobj) {
|
||||
const char* p = prefix ? prefix : "";
|
||||
const char* s = suffix ? suffix : "";
|
||||
if ((textFlags & PREC2) == PREC2) {
|
||||
lv_label_set_text_fmt(lvobj, "%s%" PRId32 ".%02" PRIu32 "%s", p,
|
||||
value / 100, (uint32_t)abs(value % 100), s);
|
||||
} else if (textFlags & PREC1) {
|
||||
lv_label_set_text_fmt(lvobj, "%s%" PRId32 ".%01" PRIu32 "%s", p,
|
||||
value / 10, (uint32_t)abs(value % 10), s);
|
||||
} else {
|
||||
lv_label_set_text_fmt(lvobj, "%s%" PRId32 "%s", p, value, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void DynamicNumber<uint16_t>::updateText()
|
||||
{
|
||||
if (lvobj) {
|
||||
const char* p = prefix ? prefix : "";
|
||||
const char* s = suffix ? suffix : "";
|
||||
if ((textFlags & PREC2) == PREC2) {
|
||||
lv_label_set_text_fmt(lvobj, "%s%" PRIu16 ".%02" PRIu16 "%s", p,
|
||||
(uint16_t)(value / 100), (uint16_t)(value % 100), s);
|
||||
} else if (textFlags & PREC1) {
|
||||
lv_label_set_text_fmt(lvobj, "%s%" PRIu16 ".%01" PRIu16 "%s", p,
|
||||
(uint16_t)(value / 10), (uint16_t)(value % 10), s);
|
||||
} else {
|
||||
lv_label_set_text_fmt(lvobj, "%s%" PRIu16 "%s", p, value, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void DynamicNumber<int16_t>::updateText()
|
||||
{
|
||||
if (lvobj) {
|
||||
const char* p = prefix ? prefix : "";
|
||||
const char* s = suffix ? suffix : "";
|
||||
if ((textFlags & PREC2) == PREC2) {
|
||||
lv_label_set_text_fmt(lvobj, "%s%" PRId16 ".%02" PRIu16 "%s", p,
|
||||
(int16_t)(value / 100), (uint16_t)abs(value % 100), s);
|
||||
} else if (textFlags & PREC1) {
|
||||
lv_label_set_text_fmt(lvobj, "%s%" PRId16 ".%01" PRIu16 "%s", p,
|
||||
(int16_t)(value / 10), (uint16_t)abs(value % 10), s);
|
||||
} else {
|
||||
lv_label_set_text_fmt(lvobj, "%s%" PRId16 "%s", p, value, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
+198
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "window.h"
|
||||
#include "button.h" // TODO just for BUTTON_BACKGROUND
|
||||
|
||||
class StaticText: public Window
|
||||
{
|
||||
public:
|
||||
StaticText(Window *parent, const rect_t &rect, std::string text = "",
|
||||
WindowFlags windowFlags = 0, LcdFlags textFlags = 0);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override;
|
||||
#endif
|
||||
|
||||
void setText(std::string value);
|
||||
const std::string& getText() const;
|
||||
|
||||
void setBackgroundColor(LcdFlags color);
|
||||
void setBackgroudOpacity(uint32_t opa);
|
||||
void setFont(LcdFlags font);
|
||||
|
||||
|
||||
protected:
|
||||
std::string text;
|
||||
LcdFlags bgColor = 0;
|
||||
};
|
||||
|
||||
class Subtitle: public StaticText {
|
||||
public:
|
||||
Subtitle(Window * parent, const rect_t & rect, const char * text, WindowFlags windowFlags = 0, LcdFlags textFlags = 0):
|
||||
StaticText(parent, rect, text, windowFlags, textFlags | FONT(BOLD))
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "Subtitle \"" + text + "\"";
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
class StaticBitmap: public Window
|
||||
{
|
||||
public:
|
||||
StaticBitmap(Window * parent, const rect_t & rect, bool scale = false):
|
||||
Window(parent, rect),
|
||||
scale(scale)
|
||||
{
|
||||
}
|
||||
|
||||
StaticBitmap(Window * parent, const rect_t & rect, const char * filename, bool scale = false):
|
||||
Window(parent, rect),
|
||||
bitmap(BitmapBuffer::loadBitmap(filename)),
|
||||
scale(scale)
|
||||
{
|
||||
}
|
||||
|
||||
StaticBitmap(Window * parent, const rect_t & rect, const BitmapBuffer * bitmap, bool scale = false):
|
||||
Window(parent, rect),
|
||||
bitmap(bitmap),
|
||||
scale(scale)
|
||||
{
|
||||
}
|
||||
|
||||
StaticBitmap(Window * parent, const rect_t & rect, const BitmapBuffer * mask, LcdFlags color, bool scale = false):
|
||||
Window(parent, rect),
|
||||
bitmap(mask),
|
||||
color(color),
|
||||
scale(scale)
|
||||
{
|
||||
}
|
||||
|
||||
void setBitmap(const char * filename)
|
||||
{
|
||||
setBitmap(BitmapBuffer::loadBitmap(filename));
|
||||
}
|
||||
|
||||
void setMaskColor(LcdFlags value)
|
||||
{
|
||||
color = value;
|
||||
}
|
||||
|
||||
void setBitmap(const BitmapBuffer * newBitmap)
|
||||
{
|
||||
delete bitmap;
|
||||
bitmap = newBitmap;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "StaticBitmap";
|
||||
}
|
||||
#endif
|
||||
|
||||
void paint(BitmapBuffer * dc) override
|
||||
{
|
||||
if (bitmap) {
|
||||
if (color != 0xFFFFFFFF)
|
||||
dc->drawMask(0, 0, bitmap, color);
|
||||
else if (scale)
|
||||
dc->drawScaledBitmap(bitmap, 0, 0, width(), height());
|
||||
else
|
||||
dc->drawBitmap((width() - bitmap->width()) / 2, (height() - bitmap->height()) / 2, bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
const BitmapBuffer * bitmap = nullptr;
|
||||
LcdFlags color = 0xFFFFFFFF;
|
||||
bool scale = false;
|
||||
};
|
||||
|
||||
class DynamicText : public StaticText
|
||||
{
|
||||
public:
|
||||
DynamicText(Window *parent, const rect_t &rect,
|
||||
std::function<std::string()> textHandler,
|
||||
LcdFlags textFlags = 0) :
|
||||
StaticText(parent, rect, "", 0, textFlags),
|
||||
textHandler(std::move(textHandler))
|
||||
{
|
||||
}
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
StaticText::checkEvents();
|
||||
setText(textHandler());
|
||||
}
|
||||
|
||||
protected:
|
||||
std::function<std::string()> textHandler;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class DynamicNumber : public StaticText
|
||||
{
|
||||
public:
|
||||
DynamicNumber(Window *parent, const rect_t &rect,
|
||||
std::function<T()> numberHandler, LcdFlags textFlags = 0,
|
||||
const char *prefix = nullptr, const char *suffix = nullptr) :
|
||||
StaticText(parent, rect, "", 0, textFlags),
|
||||
numberHandler(std::move(numberHandler)),
|
||||
prefix(prefix),
|
||||
suffix(suffix)
|
||||
{
|
||||
updateText();
|
||||
}
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
T newValue = numberHandler();
|
||||
if (value != newValue) {
|
||||
value = newValue;
|
||||
updateText();
|
||||
}
|
||||
}
|
||||
|
||||
void setPrefix(const char * value) {
|
||||
prefix = value;
|
||||
updateText();
|
||||
}
|
||||
|
||||
void setSuffix(const char * value) {
|
||||
suffix = value;
|
||||
updateText();
|
||||
}
|
||||
|
||||
protected:
|
||||
T value = 0;
|
||||
std::function<T()> numberHandler;
|
||||
const char *prefix;
|
||||
const char *suffix;
|
||||
|
||||
void updateText();
|
||||
};
|
||||
+270
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "table.h"
|
||||
#include "widgets/edgetx_table.h"
|
||||
|
||||
void TableField::event_cb(lv_event_t *e)
|
||||
{
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
if (code == LV_EVENT_VALUE_CHANGED) {
|
||||
clicked(e);
|
||||
} else if (code == LV_EVENT_DRAW_PART_BEGIN) {
|
||||
draw_begin(e);
|
||||
} else if (code == LV_EVENT_DRAW_PART_END) {
|
||||
draw_end(e);
|
||||
}
|
||||
else if (code == LV_EVENT_DRAW_POST) {
|
||||
|
||||
lv_obj_t * obj = lv_event_get_target(e);
|
||||
bool has_focus = lv_obj_has_state(obj, LV_STATE_FOCUS_KEY);
|
||||
bool is_edited = lv_group_get_editing((lv_group_t*)lv_obj_get_group(obj));
|
||||
|
||||
if (has_focus && !is_edited) {
|
||||
lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e);
|
||||
|
||||
lv_draw_rect_dsc_t rect_dsc;
|
||||
lv_draw_rect_dsc_init(&rect_dsc);
|
||||
rect_dsc.bg_opa = LV_OPA_TRANSP;
|
||||
rect_dsc.bg_img_opa = LV_OPA_TRANSP;
|
||||
rect_dsc.outline_opa = LV_OPA_TRANSP;
|
||||
rect_dsc.shadow_opa = LV_OPA_TRANSP;
|
||||
|
||||
rect_dsc.border_color = makeLvColor(COLOR_THEME_FOCUS);
|
||||
rect_dsc.border_opa = LV_OPA_100;
|
||||
rect_dsc.border_width = lv_dpx(2);
|
||||
|
||||
lv_area_t coords;
|
||||
lv_area_copy(&coords, &obj->coords);
|
||||
|
||||
lv_draw_rect(draw_ctx, &rect_dsc, &coords);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TableField::clicked(lv_event_t *e)
|
||||
{
|
||||
lv_obj_t* target = lv_event_get_target(e);
|
||||
if (!target) return;
|
||||
|
||||
TableField* tf = (TableField*)lv_obj_get_user_data(target);
|
||||
if (!tf) return;
|
||||
|
||||
uint16_t row;
|
||||
uint16_t col;
|
||||
lv_table_get_selected_cell(target, &row, &col);
|
||||
if (row == LV_TABLE_CELL_NONE || col == LV_TABLE_CELL_NONE)
|
||||
return;
|
||||
|
||||
lv_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act());
|
||||
if(indev_type == LV_INDEV_TYPE_ENCODER) {
|
||||
// Encoder send VALUE_CHANGED when selection changes
|
||||
tf->adjustScroll();
|
||||
tf->onSelected(row, col);
|
||||
} else {
|
||||
// Otherwise it's a click
|
||||
if (lv_group_get_editing((lv_group_t*)lv_obj_get_group(target))
|
||||
|| indev_type == LV_INDEV_TYPE_POINTER) {
|
||||
|
||||
tf->onPress(row, col);
|
||||
} else {
|
||||
tf->onClicked();
|
||||
}
|
||||
|
||||
// Note: VALUE_CHANGED is generated on RELEASED
|
||||
//
|
||||
// It must be avoided that CLICKED be generated afterwards
|
||||
// in case the object has been deleted meanwhile and to
|
||||
// avoid onClicked() being called.
|
||||
//
|
||||
lv_indev_reset(lv_indev_get_act(), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void TableField::draw_begin(lv_event_t* e)
|
||||
{
|
||||
lv_obj_draw_part_dsc_t* dsc = lv_event_get_draw_part_dsc(e);
|
||||
if (dsc->part != LV_PART_ITEMS) return;
|
||||
|
||||
lv_obj_t* table = lv_event_get_target(e);
|
||||
if (!table) return;
|
||||
|
||||
uint16_t cols = lv_table_get_col_cnt(table);
|
||||
if (cols == 0) return;
|
||||
|
||||
TableField* tf = (TableField*)lv_obj_get_user_data(table);
|
||||
if (!tf) return;
|
||||
|
||||
uint16_t row = dsc->id / cols;
|
||||
uint16_t col = dsc->id % cols;
|
||||
tf->onDrawBegin(row, col, dsc);
|
||||
}
|
||||
|
||||
void TableField::draw_end(lv_event_t* e)
|
||||
{
|
||||
lv_obj_draw_part_dsc_t* dsc = lv_event_get_draw_part_dsc(e);
|
||||
if (dsc->part != LV_PART_ITEMS) return;
|
||||
|
||||
lv_obj_t* table = lv_event_get_target(e);
|
||||
if (!table) return;
|
||||
|
||||
uint16_t cols = lv_table_get_col_cnt(table);
|
||||
if (cols == 0) return;
|
||||
|
||||
TableField* tf = (TableField*)lv_obj_get_user_data(table);
|
||||
if (!tf) return;
|
||||
|
||||
uint16_t row = dsc->id / cols;
|
||||
uint16_t col = dsc->id % cols;
|
||||
tf->onDrawEnd(row, col, dsc);
|
||||
}
|
||||
|
||||
TableField::TableField(Window* parent, const rect_t& rect, WindowFlags windowFlags) :
|
||||
Window(parent, rect, windowFlags, 0, table_create)
|
||||
{
|
||||
lv_obj_add_event_cb(lvobj, TableField::event_cb, LV_EVENT_ALL, nullptr);
|
||||
}
|
||||
|
||||
void TableField::setColumnCount(uint16_t cols)
|
||||
{
|
||||
lv_table_set_col_cnt(lvobj, cols);
|
||||
}
|
||||
|
||||
uint16_t TableField::getColumnCount() const
|
||||
{
|
||||
return lv_table_get_col_cnt(lvobj);
|
||||
}
|
||||
|
||||
void TableField::setRowCount(uint16_t rows)
|
||||
{
|
||||
lv_table_set_row_cnt(lvobj, rows);
|
||||
}
|
||||
|
||||
uint16_t TableField::getRowCount() const
|
||||
{
|
||||
return lv_table_get_row_cnt(lvobj);
|
||||
}
|
||||
|
||||
void TableField::setColumnWidth(uint16_t col, coord_t w)
|
||||
{
|
||||
lv_table_set_col_width(lvobj, col, w);
|
||||
}
|
||||
|
||||
coord_t TableField::getColumnWidth(uint16_t col) const
|
||||
{
|
||||
return lv_table_get_col_width(lvobj, col);
|
||||
}
|
||||
|
||||
void TableField::select(uint16_t row, uint16_t col)
|
||||
{
|
||||
lv_table_t* table = (lv_table_t*)lvobj;
|
||||
if (table->row_act == row && table->col_act == row) return;
|
||||
|
||||
if (row >= table->row_cnt || col >= table->col_cnt) {
|
||||
table->col_act = LV_TABLE_CELL_NONE;
|
||||
table->row_act = LV_TABLE_CELL_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
table->row_act = row;
|
||||
table->col_act = col;
|
||||
|
||||
lv_obj_invalidate(lvobj);
|
||||
adjustScroll();
|
||||
}
|
||||
|
||||
void TableField::adjustScroll()
|
||||
{
|
||||
lv_table_t* table = (lv_table_t*)lvobj;
|
||||
|
||||
// only vertical scroll for now
|
||||
lv_coord_t h_before = 0;
|
||||
for (uint16_t i = 0; i < table->row_act; i++) h_before += table->row_h[i];
|
||||
|
||||
lv_coord_t row_h = table->row_h[table->row_act];
|
||||
lv_coord_t scroll_y = lv_obj_get_scroll_y(lvobj);
|
||||
|
||||
lv_obj_update_layout(lvobj);
|
||||
lv_coord_t h = lv_obj_get_height(lvobj);
|
||||
|
||||
lv_coord_t diff_y = 0;
|
||||
if (h_before < scroll_y) {
|
||||
diff_y = scroll_y - h_before;
|
||||
} else if (scroll_y + h < h_before + row_h) {
|
||||
diff_y = scroll_y + h - h_before - row_h;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
lv_obj_scroll_by_bounded(lvobj, 0, diff_y, LV_ANIM_OFF);
|
||||
}
|
||||
|
||||
void TableField::selectNext(int16_t dir)
|
||||
{
|
||||
lv_table_t* table = (lv_table_t*)lvobj;
|
||||
|
||||
if (table->col_act == LV_TABLE_CELL_NONE ||
|
||||
table->row_act == LV_TABLE_CELL_NONE) {
|
||||
|
||||
if (table->col_cnt > 0 && table->row_cnt > 0) {
|
||||
table->col_act = 0;
|
||||
table->row_act = 0;
|
||||
}
|
||||
} else {
|
||||
table->col_act += dir;
|
||||
if (table->col_act >= table->col_cnt) {
|
||||
|
||||
table->col_act = 0;
|
||||
table->row_act += dir;
|
||||
|
||||
if (table->row_act >= table->row_cnt) {
|
||||
table->col_act = LV_TABLE_CELL_NONE;
|
||||
table->row_act = LV_TABLE_CELL_NONE;
|
||||
|
||||
// wrap around
|
||||
if (table->col_cnt > 0 && table->row_cnt > 0) {
|
||||
|
||||
if (dir < 0) {
|
||||
table->col_act = table->col_cnt - 1;
|
||||
table->row_act = table->row_cnt - 1;
|
||||
} else {
|
||||
table->col_act = 0;
|
||||
table->row_act = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lv_obj_invalidate(lvobj);
|
||||
adjustScroll();
|
||||
}
|
||||
|
||||
void TableField::onEvent(event_t event)
|
||||
{
|
||||
if (event == EVT_ROTARY_RIGHT) {
|
||||
selectNext(1);
|
||||
}
|
||||
else if (event == EVT_ROTARY_LEFT) {
|
||||
selectNext(-1);
|
||||
}
|
||||
else {
|
||||
Window::onEvent(event);
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "form.h"
|
||||
|
||||
class TableField : public Window
|
||||
{
|
||||
public:
|
||||
TableField(Window* parent, const rect_t& rect,
|
||||
WindowFlags windowFlags = OPAQUE | FORM_NO_BORDER);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override { return "Table"; }
|
||||
#endif
|
||||
|
||||
void setColumnCount(uint16_t cols);
|
||||
uint16_t getColumnCount() const;
|
||||
|
||||
void setRowCount(uint16_t rows);
|
||||
uint16_t getRowCount() const;
|
||||
|
||||
void setColumnWidth(uint16_t col, coord_t w);
|
||||
coord_t getColumnWidth(uint16_t col) const;
|
||||
|
||||
void select(uint16_t row, uint16_t col);
|
||||
virtual void onPress(uint16_t row, uint16_t col) {}
|
||||
|
||||
protected:
|
||||
void adjustScroll();
|
||||
void selectNext(int16_t dir);
|
||||
void onEvent(event_t event) override;
|
||||
|
||||
virtual void onSelected(uint16_t row, uint16_t col) {}
|
||||
virtual void onDrawBegin(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) {}
|
||||
virtual void onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) {}
|
||||
|
||||
static void event_cb(lv_event_t *e);
|
||||
static void clicked(lv_event_t *e);
|
||||
static void draw_begin(lv_event_t *e);
|
||||
static void draw_end(lv_event_t *e);
|
||||
};
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "textedit.h"
|
||||
#include "font.h"
|
||||
|
||||
#include "widgets/field_edit.h"
|
||||
|
||||
#if !defined(STR_EDIT)
|
||||
#define STR_EDIT "Edit"
|
||||
#endif
|
||||
|
||||
#if !defined(STR_CLEAR)
|
||||
#define STR_CLEAR "Clear"
|
||||
#endif
|
||||
|
||||
#include "keyboard_text.h"
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
#include "menu.h"
|
||||
#endif
|
||||
|
||||
#if defined(CLIPBOARD)
|
||||
#include "clipboard.h"
|
||||
#endif
|
||||
|
||||
TextEdit::TextEdit(Window *parent, const rect_t &rect, char *value,
|
||||
uint8_t length, LcdFlags windowFlags) :
|
||||
FormField(parent, rect, windowFlags, 0,
|
||||
field_edit_create),
|
||||
value(value),
|
||||
length(length)
|
||||
{
|
||||
// properties
|
||||
lv_obj_set_scrollbar_mode(lvobj, LV_SCROLLBAR_MODE_OFF);
|
||||
lv_textarea_set_password_mode(lvobj, false);
|
||||
lv_textarea_set_one_line(lvobj, true);
|
||||
|
||||
lv_textarea_set_placeholder_text(lvobj, "---");
|
||||
lv_textarea_set_max_length(lvobj, length);
|
||||
|
||||
setHeight(33);
|
||||
padTop(5);
|
||||
padLeft(4);
|
||||
lv_obj_set_style_radius(lvobj, 4, 0);
|
||||
|
||||
if (width() == 0) {
|
||||
lv_obj_set_width(lvobj, LV_DPI_DEF);
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void TextEdit::update()
|
||||
{
|
||||
// value may not be null-terminated
|
||||
std::string txt(value, length);
|
||||
lv_textarea_set_text(lvobj, txt.c_str());
|
||||
}
|
||||
|
||||
void TextEdit::trim()
|
||||
{
|
||||
for (int i = length - 1; i >= 0; i--) {
|
||||
if (value[i] == ' ' || value[i] == '\0')
|
||||
value[i] = '\0';
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TextEdit::changeEnd(bool forceChanged)
|
||||
{
|
||||
if (lvobj == nullptr) return;
|
||||
|
||||
bool changed = false;
|
||||
auto text = lv_textarea_get_text(lvobj);
|
||||
if (strncmp(value, text, length) != 0) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed || forceChanged) {
|
||||
strncpy(value, text, length);
|
||||
trim();
|
||||
FormField::changeEnd();
|
||||
}
|
||||
}
|
||||
|
||||
void TextEdit::onClicked()
|
||||
{
|
||||
TextKeyboard::show(this);
|
||||
}
|
||||
|
||||
void TextEdit::onFocusLost()
|
||||
{
|
||||
changeEnd();
|
||||
FormField::onFocusLost();
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "form.h"
|
||||
|
||||
class TextEdit : public FormField
|
||||
{
|
||||
|
||||
public:
|
||||
TextEdit(Window* parent, const rect_t& rect, char* value, uint8_t length,
|
||||
LcdFlags windowFlags = 0);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override { return "TextEdit"; }
|
||||
#endif
|
||||
|
||||
uint8_t getMaxLength() const { return length; }
|
||||
char* getData() const { return value; }
|
||||
|
||||
void update();
|
||||
|
||||
protected:
|
||||
static void event_cb(lv_event_t* e);
|
||||
|
||||
char* value;
|
||||
uint8_t length;
|
||||
|
||||
void trim();
|
||||
|
||||
void changeEnd(bool forceChanged = false) override;
|
||||
void onClicked() override;
|
||||
void onFocusLost() override;
|
||||
};
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bitmapbuffer.h"
|
||||
#include "checkbox.h"
|
||||
#include "button.h"
|
||||
|
||||
class Menu;
|
||||
class MenuWindowContent;
|
||||
class Dialog;
|
||||
class DialogWindowContent;
|
||||
class ChoiceBase;
|
||||
|
||||
enum IconState {
|
||||
STATE_DEFAULT,
|
||||
STATE_PRESSED,
|
||||
};
|
||||
|
||||
class Theme {
|
||||
public:
|
||||
virtual void drawProgressBar(BitmapBuffer * dc, coord_t x, coord_t y,
|
||||
coord_t w, coord_t h, int value, int total) const = 0;
|
||||
|
||||
virtual void drawCheckBox(BitmapBuffer* dc, CheckBox* checkBox) const
|
||||
{
|
||||
drawCheckBox(dc, checkBox->getValue(), 0, FIELD_PADDING_TOP,
|
||||
checkBox->hasFocus());
|
||||
const char* label = checkBox->getLabel();
|
||||
if (label) dc->drawText(22, FIELD_PADDING_TOP, label);
|
||||
}
|
||||
|
||||
virtual void drawCheckBox(BitmapBuffer * dc, bool checked, coord_t x, coord_t y, bool focus = false) const = 0;
|
||||
virtual const BitmapBuffer * getIcon(uint8_t index, IconState state) const = 0;
|
||||
virtual const BitmapBuffer * getIconMask(uint8_t index) const = 0;
|
||||
|
||||
virtual TextButton * createTextButton(FormGroup * parent, const rect_t & rect, std::string text, std::function<uint8_t(void)> pressHandler = nullptr, WindowFlags windowFlags = OPAQUE | BUTTON_BACKGROUND) const
|
||||
{
|
||||
return new TextButton(parent, rect, text, pressHandler, windowFlags);
|
||||
}
|
||||
};
|
||||
|
||||
extern Theme * theme;
|
||||
|
||||
MenuWindowContent * createMenuWindow(Menu * menu);
|
||||
DialogWindowContent * createDialogWindow(Dialog * dialog, const rect_t & rect);
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
|
||||
#include "edgetx_table.h"
|
||||
|
||||
|
||||
#define MY_CLASS &table_class
|
||||
|
||||
static void table_event(const lv_obj_class_t * class_p, lv_event_t * e);
|
||||
|
||||
const lv_obj_class_t table_class = {
|
||||
.constructor_cb = NULL,
|
||||
.destructor_cb = NULL,
|
||||
.event_cb = table_event,
|
||||
.width_def = LV_SIZE_CONTENT,
|
||||
.height_def = LV_SIZE_CONTENT,
|
||||
.base_class = &lv_table_class,
|
||||
.editable = LV_OBJ_CLASS_EDITABLE_TRUE,
|
||||
.group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE,
|
||||
.instance_size = 0,
|
||||
};
|
||||
|
||||
|
||||
lv_obj_t * table_create(lv_obj_t * parent)
|
||||
{
|
||||
lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
|
||||
lv_obj_class_init_obj(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
static void table_event(const lv_obj_class_t * class_p, lv_event_t * e)
|
||||
{
|
||||
lv_res_t res;
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
if (code != LV_EVENT_RELEASED) {
|
||||
/*Call the ancestor's event handler*/
|
||||
res = lv_obj_event_base(MY_CLASS, e);
|
||||
if(res != LV_RES_OK) return;
|
||||
} else {
|
||||
lv_obj_t * obj = lv_event_get_target(e);
|
||||
lv_table_t * table = (lv_table_t *)obj;
|
||||
|
||||
/*From lv_table.c: handler for LV_EVENT_RELEASED*/
|
||||
lv_obj_invalidate(obj);
|
||||
lv_indev_t* indev = lv_indev_get_act();
|
||||
lv_obj_t* scroll_obj = lv_indev_get_scroll_obj(indev);
|
||||
if (table->col_act != LV_TABLE_CELL_NONE &&
|
||||
table->row_act != LV_TABLE_CELL_NONE && scroll_obj == NULL) {
|
||||
res = lv_event_send(obj, LV_EVENT_VALUE_CHANGED, NULL);
|
||||
if (res != LV_RES_OK) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef EDGETX_TABLE_H
|
||||
#define EDGETX_TABLE_H
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const lv_obj_class_t table_class;
|
||||
lv_obj_t* table_create(lv_obj_t* parent);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "field_edit.h"
|
||||
|
||||
#define MY_CLASS &field_edit_class
|
||||
|
||||
static void field_edit_event(const lv_obj_class_t* class_p, lv_event_t* e)
|
||||
{
|
||||
/* Call the ancestor's event handler */
|
||||
lv_obj_event_base(MY_CLASS, e);
|
||||
}
|
||||
|
||||
const lv_obj_class_t field_edit_class = {
|
||||
.base_class = &lv_textarea_class,
|
||||
.event_cb = field_edit_event,
|
||||
.width_def = LV_DPI_DEF / 2,
|
||||
.height_def = LV_SIZE_CONTENT,
|
||||
.editable = LV_OBJ_CLASS_EDITABLE_TRUE,
|
||||
.group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE,
|
||||
.instance_size = sizeof(lv_textarea_t)
|
||||
};
|
||||
|
||||
lv_obj_t* field_edit_create(lv_obj_t* parent)
|
||||
{
|
||||
lv_obj_t* obj = lv_obj_class_create_obj(MY_CLASS, parent);
|
||||
lv_obj_class_init_obj(obj);
|
||||
return obj;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef FIELD_EDIT_H
|
||||
#define FIELD_EDIT_H
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const lv_obj_class_t field_edit_class;
|
||||
lv_obj_t* field_edit_create(lv_obj_t* parent);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "field_edit.h"
|
||||
|
||||
#define MY_CLASS &field_edit_class
|
||||
|
||||
const lv_obj_class_t field_edit_class = {
|
||||
.base_class = &lv_obj_class,
|
||||
.constructor_cb = lv_textarea_class.constructor_cb,
|
||||
.destructor_cb = lv_textarea_class.destructor_cb,
|
||||
.event_cb = lv_textarea_class.event_cb,
|
||||
.width_def = LV_DPI_DEF / 2,
|
||||
.height_def = LV_SIZE_CONTENT,
|
||||
.editable = LV_OBJ_CLASS_EDITABLE_TRUE,
|
||||
.group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE,
|
||||
.instance_size = sizeof(lv_textarea_t)
|
||||
};
|
||||
|
||||
lv_obj_t* field_edit_create(lv_obj_t* parent)
|
||||
{
|
||||
lv_obj_t* obj = lv_obj_class_create_obj(MY_CLASS, parent);
|
||||
lv_obj_class_init_obj(obj);
|
||||
return obj;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef FIELD_EDIT_H
|
||||
#define FIELD_EDIT_H
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const lv_obj_class_t field_edit_class;
|
||||
lv_obj_t* field_edit_create(lv_obj_t* parent);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "simple_btn.h"
|
||||
|
||||
#define MY_CLASS &simple_btn_class
|
||||
|
||||
const lv_obj_class_t simple_btn_class = {
|
||||
.width_def = LV_DPI_DEF,
|
||||
.height_def = LV_DPI_DEF,
|
||||
.group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE,
|
||||
.instance_size = sizeof(lv_btn_t),
|
||||
.base_class = &lv_btn_class,
|
||||
};
|
||||
|
||||
lv_obj_t* simple_btn_create(lv_obj_t* parent)
|
||||
{
|
||||
LV_LOG_INFO("begin");
|
||||
lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
|
||||
lv_obj_class_init_obj(obj);
|
||||
return obj;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef SIMPLE_BTN_H
|
||||
#define SIMPLE_BTN_H
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const lv_obj_class_t simple_btn_class;
|
||||
lv_obj_t* simple_btn_create(lv_obj_t* parent);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "window_base.h"
|
||||
|
||||
void window_event_cb(lv_event_t* e);
|
||||
|
||||
#define MY_CLASS &window_base_class
|
||||
|
||||
static void window_base_event(const lv_obj_class_t* class_p, lv_event_t* e);
|
||||
|
||||
const lv_obj_class_t window_base_class = {
|
||||
.base_class = &lv_obj_class,
|
||||
.event_cb = window_base_event,
|
||||
.width_def = LV_DPI_DEF,
|
||||
.height_def = LV_DPI_DEF,
|
||||
.editable = LV_OBJ_CLASS_EDITABLE_FALSE,
|
||||
.group_def = LV_OBJ_CLASS_GROUP_DEF_FALSE,
|
||||
.instance_size = sizeof(lv_obj_t)
|
||||
};
|
||||
|
||||
static void window_base_event(const lv_obj_class_t* class_p, lv_event_t* e)
|
||||
{
|
||||
/* Call the ancestor's event handler */
|
||||
lv_res_t res = lv_obj_event_base(MY_CLASS, e);
|
||||
if (res != LV_RES_OK) return;
|
||||
|
||||
window_event_cb(e);
|
||||
}
|
||||
|
||||
lv_obj_t* window_create(lv_obj_t* parent)
|
||||
{
|
||||
lv_obj_t* obj = lv_obj_class_create_obj(MY_CLASS, parent);
|
||||
lv_obj_class_init_obj(obj);
|
||||
return obj;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef WINDOW_BASE_H
|
||||
#define WINDOW_BASE_H
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const lv_obj_class_t window_base_class;
|
||||
lv_obj_t* window_create(lv_obj_t* parent);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+639
@@ -0,0 +1,639 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "window.h"
|
||||
#include "touch.h"
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include "widgets/window_base.h"
|
||||
|
||||
std::list<Window *> Window::trash;
|
||||
|
||||
extern lv_obj_t *virtual_kb;
|
||||
|
||||
extern "C" void window_event_cb(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t *target = lv_event_get_target(e);
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
|
||||
if (code == LV_EVENT_SCROLL_BEGIN) {
|
||||
TRACE("SCROLL_BEGIN");
|
||||
} else if (code == LV_EVENT_SCROLL_END) {
|
||||
TRACE("SCROLL_END");
|
||||
}
|
||||
|
||||
Window* window = (Window *)lv_obj_get_user_data(target);
|
||||
if (!window) return;
|
||||
|
||||
if(code == LV_EVENT_DELETE || window->deleted()) return;
|
||||
|
||||
if (code == LV_EVENT_DRAW_MAIN) {
|
||||
|
||||
lv_draw_ctx_t* draw_ctx = lv_event_get_draw_ctx(e);
|
||||
|
||||
lv_area_t a, clipping, obj_coords;
|
||||
lv_area_copy(&a, draw_ctx->buf_area);
|
||||
lv_area_copy(&clipping, draw_ctx->clip_area);
|
||||
lv_obj_get_coords(target, &obj_coords);
|
||||
|
||||
auto w = a.x2 - a.x1 + 1;
|
||||
auto h = a.y2 - a.y1 + 1;
|
||||
|
||||
TRACE_WINDOWS("DRAW_MAIN %s", window->getWindowDebugString().c_str());
|
||||
|
||||
BitmapBuffer buf = {BMP_RGB565, (uint16_t)w, (uint16_t)h,
|
||||
(uint16_t *)draw_ctx->buf};
|
||||
|
||||
buf.setDrawCtx(draw_ctx);
|
||||
|
||||
buf.setOffset(obj_coords.x1 - a.x1, obj_coords.y1 - a.y1);
|
||||
buf.setClippingRect(clipping.x1 - a.x1, clipping.x2 + 1 - a.x1,
|
||||
clipping.y1 - a.y1, clipping.y2 + 1 - a.y1);
|
||||
|
||||
window->paint(&buf);
|
||||
|
||||
}
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
else if (code == LV_EVENT_PRESSED || code == LV_EVENT_RELEASED) {
|
||||
TRACE_WINDOWS("PRESSED: %s", window->getWindowDebugString().c_str());
|
||||
|
||||
lv_indev_t *click_source = (lv_indev_t *)lv_event_get_param(e);
|
||||
// if(lv_indev_get_type(click_source) == LV_INDEV_TYPE_KEYPAD ||
|
||||
// lv_indev_get_type(click_source) == LV_INDEV_TYPE_ENCODER) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
lv_area_t obj_coords;
|
||||
lv_obj_get_coords(target, &obj_coords);
|
||||
|
||||
lv_point_t point_act;
|
||||
lv_indev_get_point(click_source, &point_act);
|
||||
|
||||
// Ignore event from keypad
|
||||
if (point_act.x < 0 || point_act.y < 0) return;
|
||||
|
||||
lv_point_t rel_pos;
|
||||
rel_pos.x = point_act.x - obj_coords.x1;
|
||||
rel_pos.y = point_act.y - obj_coords.y1;
|
||||
|
||||
|
||||
if (code == LV_EVENT_PRESSED) {
|
||||
TRACE("PRESSED[%d|%d]", rel_pos.x, rel_pos.y);
|
||||
window->onTouchStart(rel_pos.x, rel_pos.y);
|
||||
} else {
|
||||
lv_point_t vect_act;
|
||||
lv_indev_get_vect(click_source, &vect_act);
|
||||
|
||||
TRACE("RELEASED[%d|%d] vect[%d|%d]", rel_pos.x, rel_pos.y, vect_act.x,
|
||||
vect_act.y, lv_indev_get_scroll_dir(click_source));
|
||||
|
||||
if (vect_act.x != 0 || vect_act.y != 0) return;
|
||||
window->onTouchEnd(rel_pos.x, rel_pos.y);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (code == LV_EVENT_SCROLL) {
|
||||
|
||||
// exclude pointer based scrolling (only focus scrolling)
|
||||
if (!lv_obj_is_scrolling(target)) {
|
||||
lv_point_t* p = (lv_point_t*)lv_event_get_param(e);
|
||||
lv_coord_t scroll_bottom = lv_obj_get_scroll_bottom(target);
|
||||
|
||||
lv_coord_t scroll_y = lv_obj_get_scroll_y(target);
|
||||
TRACE("SCROLL[x=%d;y=%d;top=%d;bottom=%d]", p->x, p->y,
|
||||
scroll_y, scroll_bottom);
|
||||
|
||||
if (scroll_y <= 45 && p->y > 0) {
|
||||
lv_obj_scroll_by(target, 0, scroll_y, LV_ANIM_OFF);
|
||||
} else if (scroll_bottom <= 16 && p->y < 0) {
|
||||
lv_obj_scroll_by(target, 0, -scroll_bottom, LV_ANIM_OFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (code == LV_EVENT_CLICKED) {
|
||||
TRACE("CLICKED[%p]", window);
|
||||
window->onClicked();
|
||||
}
|
||||
else if (code == LV_EVENT_CANCEL) {
|
||||
TRACE("CANCEL[%p]", window);
|
||||
window->onCancel();
|
||||
} else if (code == LV_EVENT_FOCUSED) {
|
||||
if(window->focusHandler)
|
||||
window->focusHandler(true);
|
||||
} else if (code == LV_EVENT_DEFOCUSED) {
|
||||
if(window->focusHandler)
|
||||
window->focusHandler(false);
|
||||
}
|
||||
}
|
||||
|
||||
Window::Window(Window *parent, const rect_t &rect, WindowFlags windowFlags,
|
||||
LcdFlags textFlags, LvglCreate objConstruct) :
|
||||
rect(rect),
|
||||
parent(parent),
|
||||
windowFlags(windowFlags),
|
||||
textFlags(textFlags)
|
||||
{
|
||||
lv_obj_t* lv_parent = nullptr;
|
||||
if (parent) lv_parent = parent->lvobj;
|
||||
|
||||
if (objConstruct != nullptr && objConstruct != window_create) {
|
||||
lvobj = objConstruct(lv_parent);
|
||||
lv_obj_add_event_cb(lvobj, window_event_cb, LV_EVENT_ALL, nullptr);
|
||||
} else {
|
||||
lvobj = window_create(lv_parent);
|
||||
}
|
||||
|
||||
lv_obj_set_user_data(lvobj, this);
|
||||
|
||||
if (rect.w || rect.h) {
|
||||
lv_obj_set_pos(lvobj, rect.x, rect.y);
|
||||
lv_obj_set_size(lvobj, rect.w, rect.h);
|
||||
}
|
||||
|
||||
if (windowFlags & OPAQUE) {
|
||||
lv_obj_set_style_bg_opa(lvobj, LV_OPA_MAX, LV_PART_MAIN);
|
||||
}
|
||||
|
||||
lv_obj_set_scrollbar_mode(lvobj, LV_SCROLLBAR_MODE_OFF);
|
||||
lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_SCROLL_ELASTIC);
|
||||
|
||||
if (parent) {
|
||||
parent->addChild(this);
|
||||
if (!(windowFlags & TRANSPARENT)) {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// honor the no focus flag of libopenui
|
||||
if (this->windowFlags & NO_FOCUS) {
|
||||
lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICK_FOCUSABLE);
|
||||
}
|
||||
}
|
||||
|
||||
Window::Window(Window *parent, lv_obj_t* lvobj)
|
||||
: rect(nullRect),
|
||||
parent(parent),
|
||||
lvobj(lvobj)
|
||||
{
|
||||
lv_obj_set_user_data(lvobj, this);
|
||||
|
||||
if (windowFlags & OPAQUE) {
|
||||
lv_obj_set_style_bg_opa(lvobj, LV_OPA_MAX, LV_PART_MAIN);
|
||||
}
|
||||
|
||||
lv_obj_set_scrollbar_mode(lvobj, LV_SCROLLBAR_MODE_OFF);
|
||||
lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_SCROLL_ELASTIC);
|
||||
lv_obj_add_event_cb(lvobj, window_event_cb, LV_EVENT_ALL, this);
|
||||
|
||||
if (parent) {
|
||||
parent->addChild(this);
|
||||
if (!(windowFlags & TRANSPARENT)) {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// honor the no focus flag of libopenui
|
||||
if (this->windowFlags & NO_FOCUS) {
|
||||
lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICK_FOCUSABLE);
|
||||
}
|
||||
}
|
||||
|
||||
Window::~Window()
|
||||
{
|
||||
TRACE_WINDOWS("Destroy %p %s", this, getWindowDebugString().c_str());
|
||||
|
||||
if (children.size() > 0) deleteChildren();
|
||||
|
||||
if (lvobj != nullptr) {
|
||||
lv_obj_set_user_data(lvobj, nullptr);
|
||||
lv_obj_del(lvobj);
|
||||
lvobj = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string Window::getName() const { return "Window"; }
|
||||
|
||||
std::string Window::getRectString() const
|
||||
{
|
||||
char result[32];
|
||||
sprintf(result, "[%d, %d, %d, %d]", left(), top(), width(), height());
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string Window::getIndentString() const
|
||||
{
|
||||
std::string result;
|
||||
auto tmp = parent;
|
||||
while (tmp) {
|
||||
result += " ";
|
||||
tmp = tmp->getParent();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string Window::getWindowDebugString(const char *name) const
|
||||
{
|
||||
return getName() + (name ? std::string(" [") + name + "] " : " ") +
|
||||
getRectString();
|
||||
}
|
||||
#endif
|
||||
|
||||
Window *Window::getFullScreenWindow()
|
||||
{
|
||||
if (width() == LCD_W && height() == LCD_H) return this;
|
||||
if (parent) return parent->getFullScreenWindow();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Window::setWindowFlags(WindowFlags flags)
|
||||
{
|
||||
// TODO: check if LVGL flags need updating...
|
||||
windowFlags = flags;
|
||||
}
|
||||
|
||||
void Window::setTextFlags(LcdFlags flags)
|
||||
{
|
||||
textFlags = flags;
|
||||
if (!lvobj) return;
|
||||
|
||||
// lv integration for colors
|
||||
auto textColor = COLOR_VAL(flags);
|
||||
auto r = GET_RED(textColor), g = GET_GREEN(textColor),
|
||||
b = GET_BLUE(textColor);
|
||||
lv_obj_set_style_text_color(lvobj, lv_color_make(r, g, b), LV_PART_MAIN);
|
||||
|
||||
// // rco: shouldn't this be done via 'setTextFlags()' on the children?
|
||||
// for (uint32_t i = 0; i < lv_obj_get_child_cnt(lvobj); i++) {
|
||||
// auto child = lv_obj_get_child(lvobj, i);
|
||||
// lv_obj_set_style_text_color(child, lv_color_make(r, g, b), LV_PART_MAIN);
|
||||
// }
|
||||
}
|
||||
|
||||
void Window::attach(Window *newParent)
|
||||
{
|
||||
if (parent) detach();
|
||||
parent = newParent;
|
||||
if (newParent) {
|
||||
newParent->addChild(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Window::detach()
|
||||
{
|
||||
if (parent) {
|
||||
parent->removeChild(this);
|
||||
parent = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Window::deleteLater(bool detach, bool trash)
|
||||
{
|
||||
if (_deleted)
|
||||
return;
|
||||
|
||||
TRACE_WINDOWS("Delete %p %s", this, getWindowDebugString().c_str());
|
||||
|
||||
_deleted = true;
|
||||
|
||||
if (detach)
|
||||
this->detach();
|
||||
else
|
||||
parent = nullptr;
|
||||
|
||||
if (trash) {
|
||||
Window::trash.push_back(this);
|
||||
}
|
||||
|
||||
if (closeHandler) {
|
||||
closeHandler();
|
||||
}
|
||||
|
||||
deleteChildren();
|
||||
|
||||
if (lvobj != nullptr) {
|
||||
auto obj = lvobj;
|
||||
lvobj = nullptr;
|
||||
lv_obj_del(obj);
|
||||
}
|
||||
}
|
||||
|
||||
void Window::clear()
|
||||
{
|
||||
deleteChildren();
|
||||
if(lvobj != nullptr) {
|
||||
lv_obj_clean(lvobj);
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void Window::deleteChildren()
|
||||
{
|
||||
// prevent LVGL refocus while mass-deleting
|
||||
// inhibit_focus = true;
|
||||
for (auto window: children) {
|
||||
window->deleteLater(false);
|
||||
}
|
||||
// inhibit_focus = false;
|
||||
children.clear();
|
||||
}
|
||||
|
||||
bool Window::hasFocus() const
|
||||
{
|
||||
return lvobj && lv_obj_has_state(lvobj, LV_STATE_FOCUSED);
|
||||
}
|
||||
|
||||
void Window::padLeft(coord_t pad)
|
||||
{
|
||||
lv_obj_set_style_pad_left(lvobj, pad, 0);
|
||||
}
|
||||
|
||||
void Window::padRight(coord_t pad)
|
||||
{
|
||||
lv_obj_set_style_pad_right(lvobj, pad, 0);
|
||||
}
|
||||
|
||||
void Window::padTop(coord_t pad)
|
||||
{
|
||||
lv_obj_set_style_pad_top(lvobj, pad, 0);
|
||||
}
|
||||
|
||||
void Window::padBottom(coord_t pad)
|
||||
{
|
||||
lv_obj_set_style_pad_bottom(lvobj, pad, 0);
|
||||
}
|
||||
|
||||
void Window::padAll(coord_t pad)
|
||||
{
|
||||
lv_obj_set_style_pad_all(lvobj, pad, 0);
|
||||
}
|
||||
|
||||
void Window::padRow(coord_t pad)
|
||||
{
|
||||
lv_obj_set_style_pad_row(lvobj, pad, 0);
|
||||
}
|
||||
|
||||
void Window::padColumn(coord_t pad)
|
||||
{
|
||||
lv_obj_set_style_pad_column(lvobj, pad, 0);
|
||||
}
|
||||
|
||||
bool Window::hasOpaqueRect(const rect_t & testRect) const
|
||||
{
|
||||
if (!rect.contains(testRect))
|
||||
return false;
|
||||
|
||||
if (windowFlags & OPAQUE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
rect_t relativeRect = {testRect.x - rect.x, testRect.y - rect.y, testRect.w, testRect.h};
|
||||
for (auto child: children) {
|
||||
if (child->hasOpaqueRect(relativeRect))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Window::fullPaint(BitmapBuffer * dc)
|
||||
{
|
||||
if(lvobj != nullptr)
|
||||
lv_obj_invalidate(lvobj);
|
||||
bool paintNeeded = true;
|
||||
std::list<Window *>::iterator firstChild;
|
||||
|
||||
coord_t xmin, xmax, ymin, ymax;
|
||||
dc->getClippingRect(xmin, xmax, ymin, ymax);
|
||||
coord_t x = dc->getOffsetX();
|
||||
coord_t y = dc->getOffsetY();
|
||||
|
||||
if (windowFlags & PAINT_CHILDREN_FIRST) {
|
||||
paintChildren(dc, children.begin());
|
||||
dc->setOffset(x, y);
|
||||
dc->setClippingRect(xmin, xmax, ymin, ymax);
|
||||
}
|
||||
else {
|
||||
firstChild = children.end();
|
||||
rect_t relativeRect = {xmin - x, ymin - y, xmax - xmin, ymax - ymin};
|
||||
while (firstChild != children.begin()) {
|
||||
auto child = *(--firstChild);
|
||||
if (child->hasOpaqueRect(relativeRect)) {
|
||||
paintNeeded = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (paintNeeded) {
|
||||
TRACE_WINDOWS_INDENT("%s%s", getWindowDebugString().c_str(), hasFocus() ? " (*)" : "");
|
||||
paint(dc);
|
||||
#if defined(WINDOWS_INSPECT_BORDER_COLOR)
|
||||
dc->drawSolidRect(0, 0, width(), height(), 1, WINDOWS_INSPECT_BORDER_COLOR);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
TRACE_WINDOWS_INDENT("%s (skipped)", getWindowDebugString().c_str());
|
||||
}
|
||||
|
||||
|
||||
if (!(windowFlags & PAINT_CHILDREN_FIRST)) {
|
||||
paintChildren(dc, firstChild);
|
||||
}
|
||||
}
|
||||
|
||||
bool Window::isChildFullSize(const Window * child) const
|
||||
{
|
||||
return child->top() == 0 && child->height() == height() && child->left() == 0 && child->width() == width();
|
||||
}
|
||||
|
||||
bool Window::isChildVisible(const Window * window) const
|
||||
{
|
||||
for (auto rit = children.rbegin(); rit != children.rend(); rit++) {
|
||||
auto child = *rit;
|
||||
if (child == window) {
|
||||
return true;
|
||||
}
|
||||
if ((child->getWindowFlags() & OPAQUE) & isChildFullSize(child)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Window::paintChildren(BitmapBuffer * dc, std::list<Window *>::iterator it)
|
||||
{
|
||||
coord_t x = dc->getOffsetX();
|
||||
coord_t y = dc->getOffsetY();
|
||||
coord_t xmin, xmax, ymin, ymax;
|
||||
dc->getClippingRect(xmin, xmax, ymin, ymax);
|
||||
|
||||
for (; it != children.end(); it++) {
|
||||
auto child = *it;
|
||||
|
||||
coord_t child_xmin = x + child->rect.x;
|
||||
if (child_xmin >= xmax)
|
||||
continue;
|
||||
coord_t child_ymin = y + child->rect.y;
|
||||
if (child_ymin >= ymax)
|
||||
continue;
|
||||
coord_t child_xmax = child_xmin + child->rect.w;
|
||||
if (child_xmax <= xmin)
|
||||
continue;
|
||||
coord_t child_ymax = child_ymin + child->rect.h;
|
||||
if (child_ymax <= ymin)
|
||||
continue;
|
||||
|
||||
// dc->setOffset(x + child->rect.x - child->scrollPositionX,
|
||||
// y + child->rect.y - child->scrollPositionY);
|
||||
dc->setClippingRect(
|
||||
max(xmin, x + child->rect.left()), min(xmax, x + child->rect.right()),
|
||||
max(ymin, y + child->rect.top()), min(ymax, y + child->rect.bottom()));
|
||||
child->fullPaint(dc);
|
||||
}
|
||||
}
|
||||
|
||||
void Window::bringToTop()
|
||||
{
|
||||
attach(parent); // does a detach + attach
|
||||
if (lvobj && lv_obj_get_parent(lvobj)) lv_obj_move_foreground(lvobj);
|
||||
}
|
||||
|
||||
void Window::checkEvents()
|
||||
{
|
||||
auto copy = children;
|
||||
for (auto child: copy) {
|
||||
if (!child->deleted()) {
|
||||
child->checkEvents();
|
||||
}
|
||||
}
|
||||
|
||||
if (windowFlags & REFRESH_ALWAYS) {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::onEvent(event_t event)
|
||||
{
|
||||
TRACE_WINDOWS("%s received event 0x%X", Window::getWindowDebugString("Window").c_str(), event);
|
||||
if (parent) { parent->onEvent(event); }
|
||||
}
|
||||
|
||||
void Window::onClicked()
|
||||
{
|
||||
if (parent && !(windowFlags & OPAQUE)) { parent->onClicked(); }
|
||||
}
|
||||
|
||||
void Window::onCancel()
|
||||
{
|
||||
if (parent) { parent->onCancel(); }
|
||||
}
|
||||
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool Window::onTouchStart(coord_t x, coord_t y)
|
||||
{
|
||||
if (parent && !(windowFlags & OPAQUE)) return parent->onTouchStart(x, y);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Window::onTouchEnd(coord_t x, coord_t y)
|
||||
{
|
||||
if (parent && !(windowFlags & OPAQUE)) return parent->onTouchEnd(x, y);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Window::onTouchSlide(coord_t x, coord_t y, coord_t startX, coord_t startY, coord_t slideX, coord_t slideY)
|
||||
{
|
||||
// TODO: this is not used anymore: REMOVE
|
||||
|
||||
// for (auto it = children.rbegin(); it != children.rend(); ++it) {
|
||||
// auto child = *it;
|
||||
// if (child->rect.contains(startX, startY)) {
|
||||
// if (child->onTouchSlide(x - child->rect.x, y - child->rect.y, startX - child->rect.x, startY - child->rect.y, slideX, slideY)) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
coord_t Window::adjustHeight()
|
||||
{
|
||||
coord_t old = rect.h;
|
||||
if (lvobj) {
|
||||
lv_obj_set_height(lvobj, LV_SIZE_CONTENT);
|
||||
lv_obj_update_layout(lvobj);
|
||||
rect.h = lv_obj_get_height(lvobj);
|
||||
lv_obj_set_style_height(lvobj, rect.h, LV_PART_MAIN);
|
||||
}
|
||||
return rect.h - old;
|
||||
}
|
||||
|
||||
void Window::moveWindowsTop(coord_t y, coord_t delta)
|
||||
{
|
||||
if (getWindowFlags() & FORWARD_SCROLL) {
|
||||
parent->moveWindowsTop(bottom(), delta);
|
||||
}
|
||||
|
||||
for (auto child: children) {
|
||||
if (child->rect.y >= y) {
|
||||
child->setTop(child->top() + delta);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Window::updateSize()
|
||||
{
|
||||
lv_obj_set_height(lvobj, LV_SIZE_CONTENT);
|
||||
lv_obj_update_layout(lvobj);
|
||||
|
||||
rect.x = lv_obj_get_x(lvobj);
|
||||
rect.y = lv_obj_get_y(lvobj);
|
||||
rect.w = lv_obj_get_width(lvobj);
|
||||
rect.h = lv_obj_get_height(lvobj);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void Window::addChild(Window* window)
|
||||
{
|
||||
auto lv_parent = lv_obj_get_parent(window->lvobj);
|
||||
if (lv_parent && (lv_parent != lvobj)) {
|
||||
lv_obj_set_parent(window->lvobj, lvobj);
|
||||
}
|
||||
|
||||
children.push_back(window);
|
||||
}
|
||||
|
||||
void Window::removeChild(Window* window)
|
||||
{
|
||||
children.remove(window);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void Window::invalidate(const rect_t & rect)
|
||||
{
|
||||
if (lvobj) lv_obj_invalidate(lvobj);
|
||||
}
|
||||
+294
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
|
||||
#include "bitmapbuffer.h"
|
||||
#include "libopenui_defines.h"
|
||||
#include "libopenui_helpers.h"
|
||||
#include "libopenui_config.h"
|
||||
|
||||
#include "widgets/window_base.h"
|
||||
|
||||
#include "LvglWrapper.h"
|
||||
|
||||
typedef uint32_t WindowFlags;
|
||||
|
||||
#if !defined(_GNUC_)
|
||||
#undef OPAQUE
|
||||
#undef TRANSPARENT
|
||||
#endif
|
||||
|
||||
constexpr int INFINITE_HEIGHT = INT32_MAX;
|
||||
|
||||
constexpr WindowFlags OPAQUE = 1u << 0u;
|
||||
constexpr WindowFlags TRANSPARENT = 1u << 1u;
|
||||
constexpr WindowFlags NO_SCROLLBAR = 1u << 2u;
|
||||
constexpr WindowFlags NO_FOCUS = 1u << 3u;
|
||||
constexpr WindowFlags FORWARD_SCROLL = 1u << 4u;
|
||||
constexpr WindowFlags REFRESH_ALWAYS = 1u << 5u;
|
||||
constexpr WindowFlags PAINT_CHILDREN_FIRST = 1u << 6u;
|
||||
constexpr WindowFlags PUSH_FRONT = 1u << 7u;
|
||||
constexpr WindowFlags WINDOW_FLAGS_LAST = PUSH_FRONT;
|
||||
|
||||
// enum SetFocusFlag
|
||||
// {
|
||||
// SET_FOCUS_DEFAULT = 0,
|
||||
// SET_FOCUS_FORWARD = 1,
|
||||
// SET_FOCUS_BACKWARD = 2,
|
||||
// SET_FOCUS_FIRST = 3,
|
||||
// SET_FOCUS_NO_SCROLL= 4
|
||||
// };
|
||||
|
||||
typedef lv_obj_t *(*LvglCreate)(lv_obj_t *);
|
||||
extern "C" void window_event_cb(lv_event_t * e);
|
||||
|
||||
|
||||
class Window
|
||||
{
|
||||
friend class GridLayout;
|
||||
friend void window_event_cb(lv_event_t * e);
|
||||
|
||||
public:
|
||||
Window(Window *parent, const rect_t &rect, WindowFlags windowFlags = 0,
|
||||
LcdFlags textFlags = 0, LvglCreate objConstruct = nullptr);
|
||||
|
||||
Window(Window *parent, lv_obj_t* lvobj);
|
||||
|
||||
virtual ~Window();
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
virtual std::string getName() const;
|
||||
std::string getRectString() const;
|
||||
std::string getIndentString() const;
|
||||
std::string getWindowDebugString(const char * name = nullptr) const;
|
||||
#endif
|
||||
|
||||
Window *getParent() const { return parent; }
|
||||
|
||||
bool isChild(Window *window) const
|
||||
{
|
||||
return window == this || (parent && parent->isChild(window));
|
||||
}
|
||||
|
||||
Window *getFullScreenWindow();
|
||||
|
||||
WindowFlags getWindowFlags() const { return windowFlags; }
|
||||
void setWindowFlags(WindowFlags flags);
|
||||
|
||||
LcdFlags getTextFlags() const { return textFlags; }
|
||||
void setTextFlags(LcdFlags flags);
|
||||
|
||||
typedef std::function<void()> CloseHandler;
|
||||
void setCloseHandler(CloseHandler h) { closeHandler = std::move(h); }
|
||||
|
||||
typedef std::function<void(bool)> FocusHandler;
|
||||
void setFocusHandler(FocusHandler h) { focusHandler = std::move(h); }
|
||||
|
||||
const std::list<Window *> getChildren() { return children; }
|
||||
|
||||
void clear();
|
||||
virtual void deleteLater(bool detach = true, bool trash = true);
|
||||
|
||||
bool hasFocus() const;
|
||||
|
||||
void setRect(rect_t value)
|
||||
{
|
||||
rect = value;
|
||||
lv_obj_enable_style_refresh(false);
|
||||
lv_obj_set_pos(lvobj, rect.x, rect.y);
|
||||
lv_obj_set_width(lvobj, rect.w);
|
||||
lv_obj_enable_style_refresh(true);
|
||||
lv_obj_set_height(lvobj, rect.h);
|
||||
}
|
||||
|
||||
void setWidth(coord_t value)
|
||||
{
|
||||
rect.w = value;
|
||||
lv_obj_set_width(lvobj, rect.w);
|
||||
}
|
||||
|
||||
void setWindowCentered()
|
||||
{
|
||||
rect.x = (parent->width() - width()) / 2;
|
||||
rect.y = (parent->height() - height()) / 2;
|
||||
lv_obj_set_pos(lvobj, rect.x, rect.y);
|
||||
}
|
||||
|
||||
void setHeight(coord_t value)
|
||||
{
|
||||
rect.h = value;
|
||||
if (lvobj != nullptr) lv_obj_set_height(lvobj, rect.h);
|
||||
}
|
||||
|
||||
void setLeft(coord_t x)
|
||||
{
|
||||
rect.x = x;
|
||||
lv_obj_set_pos(lvobj, rect.x, rect.y);
|
||||
}
|
||||
|
||||
void setTop(coord_t y)
|
||||
{
|
||||
rect.y = y;
|
||||
lv_obj_set_pos(lvobj, rect.x, rect.y);
|
||||
}
|
||||
|
||||
coord_t left() const
|
||||
{
|
||||
return rect.x;
|
||||
}
|
||||
|
||||
coord_t right() const
|
||||
{
|
||||
return rect.x + rect.w;
|
||||
}
|
||||
|
||||
coord_t top() const
|
||||
{
|
||||
return rect.y;
|
||||
}
|
||||
|
||||
coord_t bottom() const
|
||||
{
|
||||
return rect.y + rect.h;
|
||||
}
|
||||
|
||||
coord_t width() const
|
||||
{
|
||||
return rect.w;
|
||||
}
|
||||
|
||||
coord_t height() const
|
||||
{
|
||||
return rect.h;
|
||||
}
|
||||
|
||||
rect_t getRect() const
|
||||
{
|
||||
return rect;
|
||||
}
|
||||
|
||||
void padLeft(coord_t pad);
|
||||
void padRight(coord_t pad);
|
||||
void padTop(coord_t pad);
|
||||
void padBottom(coord_t pad);
|
||||
void padAll(coord_t pad);
|
||||
|
||||
void padRow(coord_t pad);
|
||||
void padColumn(coord_t pad);
|
||||
|
||||
bool isChildVisible(const Window * window) const;
|
||||
bool isChildFullSize(const Window * window) const;
|
||||
|
||||
bool isVisible() const
|
||||
{
|
||||
return parent && parent->isChildVisible(this);
|
||||
}
|
||||
|
||||
virtual void onEvent(event_t event);
|
||||
virtual void onClicked();
|
||||
virtual void onCancel();
|
||||
|
||||
coord_t adjustHeight();
|
||||
|
||||
void moveWindowsTop(coord_t y, coord_t delta);
|
||||
|
||||
virtual void updateSize();
|
||||
|
||||
void invalidate()
|
||||
{
|
||||
invalidate({0, 0, rect.w, rect.h});
|
||||
}
|
||||
|
||||
void bringToTop();
|
||||
|
||||
virtual void checkEvents();
|
||||
|
||||
void attach(Window * window);
|
||||
|
||||
void detach();
|
||||
|
||||
bool deleted() const
|
||||
{
|
||||
return _deleted;
|
||||
}
|
||||
|
||||
virtual void paint(BitmapBuffer *) {}
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
virtual bool onTouchStart(coord_t x, coord_t y);
|
||||
virtual bool onTouchEnd(coord_t x, coord_t y);
|
||||
#endif
|
||||
|
||||
inline lv_obj_t *getLvObj() { return lvobj; }
|
||||
|
||||
protected:
|
||||
static std::list<Window*> trash;
|
||||
|
||||
rect_t rect;
|
||||
|
||||
Window* parent = nullptr;
|
||||
lv_obj_t* lvobj = nullptr;
|
||||
|
||||
std::list<Window *> children;
|
||||
|
||||
WindowFlags windowFlags = 0;
|
||||
LcdFlags textFlags = 0;
|
||||
|
||||
bool _deleted = false;
|
||||
|
||||
std::function<void()> closeHandler;
|
||||
std::function<void(bool)> focusHandler;
|
||||
|
||||
void deleteChildren();
|
||||
|
||||
virtual void addChild(Window * window);
|
||||
void removeChild(Window * window);
|
||||
|
||||
virtual void invalidate(const rect_t & rect);
|
||||
|
||||
void fullPaint(BitmapBuffer * dc);
|
||||
void paintChildren(BitmapBuffer * dc, std::list<Window *>::iterator it);
|
||||
|
||||
virtual void onFocusLost()
|
||||
{
|
||||
TRACE_WINDOWS("%s onFocusLost()", getWindowDebugString().c_str());
|
||||
if (focusHandler) {
|
||||
focusHandler(false);
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
virtual bool onTouchSlide(coord_t x, coord_t y, coord_t startX,
|
||||
coord_t startY, coord_t slideX, coord_t slideY);
|
||||
#endif
|
||||
|
||||
|
||||
bool hasOpaqueRect(const rect_t & testRect) const;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
set(LVGL_SOURCES_MINIMAL
|
||||
core/lv_group.c
|
||||
core/lv_obj.c
|
||||
core/lv_event.c
|
||||
core/lv_indev.c
|
||||
core/lv_obj_scroll.c
|
||||
core/lv_obj_draw.c
|
||||
core/lv_disp.c
|
||||
core/lv_obj_style.c
|
||||
core/lv_theme.c
|
||||
core/lv_obj_style_gen.c
|
||||
core/lv_refr.c
|
||||
core/lv_indev_scroll.c
|
||||
core/lv_obj_class.c
|
||||
core/lv_obj_tree.c
|
||||
core/lv_obj_pos.c
|
||||
|
||||
draw/lv_draw_mask.c
|
||||
draw/lv_img_cache.c
|
||||
draw/sw/lv_draw_sw_gradient.c
|
||||
draw/sw/lv_draw_sw.c
|
||||
draw/sw/lv_draw_sw_blend.c
|
||||
draw/sw/lv_draw_sw_letter.c
|
||||
draw/sw/lv_draw_sw_arc.c
|
||||
draw/sw/lv_draw_sw_polygon.c
|
||||
draw/sw/lv_draw_sw_img.c
|
||||
draw/sw/lv_draw_sw_line.c
|
||||
draw/sw/lv_draw_sw_dither.c
|
||||
draw/sw/lv_draw_sw_rect.c
|
||||
draw/lv_draw_line.c
|
||||
draw/lv_draw.c
|
||||
draw/lv_img_buf.c
|
||||
draw/lv_draw_rect.c
|
||||
draw/lv_draw_label.c
|
||||
draw/lv_draw_img.c
|
||||
draw/lv_draw_arc.c
|
||||
draw/lv_draw_triangle.c
|
||||
draw/lv_img_decoder.c
|
||||
|
||||
# STM32 specific
|
||||
draw/stm32_dma2d/lv_gpu_stm32_dma2d.c
|
||||
|
||||
# SDL specific
|
||||
draw/sdl/lv_draw_sdl_rect.c
|
||||
draw/sdl/lv_draw_sdl_arc.c
|
||||
draw/sdl/lv_draw_sdl.c
|
||||
draw/sdl/lv_draw_sdl_mask.c
|
||||
draw/sdl/lv_draw_sdl_polygon.c
|
||||
draw/sdl/lv_draw_sdl_stack_blur.c
|
||||
draw/sdl/lv_draw_sdl_utils.c
|
||||
draw/sdl/lv_draw_sdl_img.c
|
||||
draw/sdl/lv_draw_sdl_bg.c
|
||||
draw/sdl/lv_draw_sdl_label.c
|
||||
draw/sdl/lv_draw_sdl_texture_cache.c
|
||||
draw/sdl/lv_draw_sdl_line.c
|
||||
draw/sdl/lv_draw_sdl_composite.c
|
||||
|
||||
hal/lv_hal_indev.c
|
||||
hal/lv_hal_disp.c
|
||||
hal/lv_hal_tick.c
|
||||
|
||||
font/lv_font.c
|
||||
font/lv_font_loader.c
|
||||
font/lv_font_fmt_txt.c
|
||||
|
||||
misc/lv_timer.c
|
||||
misc/lv_txt.c
|
||||
misc/lv_gc.c
|
||||
misc/lv_style_gen.c
|
||||
misc/lv_templ.c
|
||||
misc/lv_color.c
|
||||
misc/lv_fs.c
|
||||
misc/lv_printf.c
|
||||
misc/lv_style.c
|
||||
misc/lv_log.c
|
||||
misc/lv_area.c
|
||||
misc/lv_math.c
|
||||
misc/lv_lru.c
|
||||
misc/lv_tlsf.c
|
||||
misc/lv_anim_timeline.c
|
||||
misc/lv_ll.c
|
||||
misc/lv_bidi.c
|
||||
misc/lv_mem.c
|
||||
misc/lv_utils.c
|
||||
misc/lv_async.c
|
||||
misc/lv_anim.c
|
||||
misc/lv_txt_ap.c
|
||||
|
||||
extra/lv_extra.c
|
||||
)
|
||||
|
||||
set(LVGL_SOURCES
|
||||
${LVGL_SOURCES_MINIMAL}
|
||||
# font/lv_font_unscii_8.c
|
||||
# font/lv_font_unscii_16.c
|
||||
# font/lv_font_simsun_16_cjk.c
|
||||
# font/lv_font_dejavu_16_persian_hebrew.c
|
||||
# font/lv_font_montserrat_8.c
|
||||
# font/lv_font_montserrat_10.c
|
||||
# font/lv_font_montserrat_12.c
|
||||
# font/lv_font_montserrat_12_subpx.c
|
||||
# font/lv_font_montserrat_14.c
|
||||
# font/lv_font_montserrat_16.c
|
||||
# font/lv_font_montserrat_18.c
|
||||
# font/lv_font_montserrat_20.c
|
||||
# font/lv_font_montserrat_22.c
|
||||
# font/lv_font_montserrat_24.c
|
||||
# font/lv_font_montserrat_26.c
|
||||
# font/lv_font_montserrat_28.c
|
||||
# font/lv_font_montserrat_28_compressed.c
|
||||
# font/lv_font_montserrat_30.c
|
||||
# font/lv_font_montserrat_32.c
|
||||
# font/lv_font_montserrat_34.c
|
||||
# font/lv_font_montserrat_36.c
|
||||
# font/lv_font_montserrat_38.c
|
||||
# font/lv_font_montserrat_40.c
|
||||
# font/lv_font_montserrat_42.c
|
||||
# font/lv_font_montserrat_44.c
|
||||
# font/lv_font_montserrat_46.c
|
||||
# font/lv_font_montserrat_48.c
|
||||
widgets/lv_line.c
|
||||
widgets/lv_dropdown.c
|
||||
widgets/lv_objx_templ.c
|
||||
widgets/lv_canvas.c
|
||||
widgets/lv_switch.c
|
||||
widgets/lv_btnmatrix.c
|
||||
widgets/lv_bar.c
|
||||
widgets/lv_roller.c
|
||||
widgets/lv_img.c
|
||||
widgets/lv_btn.c
|
||||
widgets/lv_checkbox.c
|
||||
widgets/lv_label.c
|
||||
widgets/lv_table.c
|
||||
widgets/lv_slider.c
|
||||
widgets/lv_textarea.c
|
||||
widgets/lv_arc.c
|
||||
extra/others/monkey/lv_monkey.c
|
||||
extra/others/gridnav/lv_gridnav.c
|
||||
extra/others/snapshot/lv_snapshot.c
|
||||
extra/layouts/grid/lv_grid.c
|
||||
extra/layouts/flex/lv_flex.c
|
||||
extra/libs/bmp/lv_bmp.c
|
||||
extra/libs/ffmpeg/lv_ffmpeg.c
|
||||
extra/libs/gif/lv_gif.c
|
||||
extra/libs/gif/gifdec.c
|
||||
extra/libs/freetype/lv_freetype.c
|
||||
extra/libs/qrcode/lv_qrcode.c
|
||||
extra/libs/qrcode/qrcodegen.c
|
||||
extra/libs/sjpg/tjpgd.c
|
||||
extra/libs/sjpg/lv_sjpg.c
|
||||
extra/libs/fsdrv/lv_fs_win32.c
|
||||
extra/libs/fsdrv/lv_fs_stdio.c
|
||||
extra/libs/fsdrv/lv_fs_posix.c
|
||||
extra/libs/fsdrv/lv_fs_fatfs.c
|
||||
extra/libs/rlottie/lv_rlottie.c
|
||||
extra/libs/png/lv_png.c
|
||||
extra/libs/png/lodepng.c
|
||||
extra/widgets/imgbtn/lv_imgbtn.c
|
||||
extra/widgets/menu/lv_menu.c
|
||||
extra/widgets/win/lv_win.c
|
||||
extra/widgets/colorwheel/lv_colorwheel.c
|
||||
extra/widgets/list/lv_list.c
|
||||
extra/widgets/chart/lv_chart.c
|
||||
extra/widgets/calendar/lv_calendar_header_arrow.c
|
||||
extra/widgets/calendar/lv_calendar.c
|
||||
extra/widgets/calendar/lv_calendar_header_dropdown.c
|
||||
extra/widgets/tileview/lv_tileview.c
|
||||
extra/widgets/led/lv_led.c
|
||||
extra/widgets/spinner/lv_spinner.c
|
||||
extra/widgets/tabview/lv_tabview.c
|
||||
extra/widgets/meter/lv_meter.c
|
||||
extra/widgets/spinbox/lv_spinbox.c
|
||||
extra/widgets/animimg/lv_animimg.c
|
||||
extra/widgets/span/lv_span.c
|
||||
extra/widgets/keyboard/lv_keyboard.c
|
||||
extra/widgets/msgbox/lv_msgbox.c
|
||||
# extra/themes/basic/lv_theme_basic.c
|
||||
# extra/themes/default/lv_theme_default.c
|
||||
# extra/themes/mono/lv_theme_mono.c
|
||||
)
|
||||
|
||||
foreach(LVGL_FILE ${LVGL_SOURCES_MINIMAL})
|
||||
set(LVGL_SRC_FILES_MINIMAL ${LVGL_SRC_FILES_MINIMAL} ${LVGL_SRC_DIR}/${LVGL_FILE})
|
||||
endforeach()
|
||||
|
||||
foreach(LVGL_FILE ${LVGL_SOURCES})
|
||||
set(LVGL_SRC_FILES ${LVGL_SRC_FILES} ${LVGL_SRC_DIR}/${LVGL_FILE})
|
||||
endforeach()
|
||||
|
||||
set(SRC ${SRC} ${LVGL_SRC_FILES})
|
||||
+1
Submodule radio/src/thirdparty/libopenui/thirdparty/lvgl added at 9a414b1d48
@@ -0,0 +1,24 @@
|
||||
LZ4 Library
|
||||
Copyright (c) 2011-2016, Yann Collet
|
||||
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.
|
||||
|
||||
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 HOLDER 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.
|
||||
@@ -0,0 +1,137 @@
|
||||
LZ4 - Library Files
|
||||
================================
|
||||
|
||||
The `/lib` directory contains many files, but depending on project's objectives,
|
||||
not all of them are necessary.
|
||||
|
||||
#### Minimal LZ4 build
|
||||
|
||||
The minimum required is **`lz4.c`** and **`lz4.h`**,
|
||||
which provides the fast compression and decompression algorithms.
|
||||
They generate and decode data using the [LZ4 block format].
|
||||
|
||||
|
||||
#### High Compression variant
|
||||
|
||||
For more compression ratio at the cost of compression speed,
|
||||
the High Compression variant called **lz4hc** is available.
|
||||
Add files **`lz4hc.c`** and **`lz4hc.h`**.
|
||||
This variant also compresses data using the [LZ4 block format],
|
||||
and depends on regular `lib/lz4.*` source files.
|
||||
|
||||
|
||||
#### Frame support, for interoperability
|
||||
|
||||
In order to produce compressed data compatible with `lz4` command line utility,
|
||||
it's necessary to use the [official interoperable frame format].
|
||||
This format is generated and decoded automatically by the **lz4frame** library.
|
||||
Its public API is described in `lib/lz4frame.h`.
|
||||
In order to work properly, lz4frame needs all other modules present in `/lib`,
|
||||
including, lz4 and lz4hc, and also **xxhash**.
|
||||
So it's necessary to include all `*.c` and `*.h` files present in `/lib`.
|
||||
|
||||
|
||||
#### Advanced / Experimental API
|
||||
|
||||
Definitions which are not guaranteed to remain stable in future versions,
|
||||
are protected behind macros, such as `LZ4_STATIC_LINKING_ONLY`.
|
||||
As the name strongly implies, these definitions should only be invoked
|
||||
in the context of static linking ***only***.
|
||||
Otherwise, dependent application may fail on API or ABI break in the future.
|
||||
The associated symbols are also not exposed by the dynamic library by default.
|
||||
Should they be nonetheless needed, it's possible to force their publication
|
||||
by using build macros `LZ4_PUBLISH_STATIC_FUNCTIONS`
|
||||
and `LZ4F_PUBLISH_STATIC_FUNCTIONS`.
|
||||
|
||||
|
||||
#### Build macros
|
||||
|
||||
The following build macro can be selected to adjust source code behavior at compilation time :
|
||||
|
||||
- `LZ4_FAST_DEC_LOOP` : this triggers a speed optimized decompression loop, more powerful on modern cpus.
|
||||
This loop works great on `x86`, `x64` and `aarch64` cpus, and is automatically enabled for them.
|
||||
It's also possible to enable or disable it manually, by passing `LZ4_FAST_DEC_LOOP=1` or `0` to the preprocessor.
|
||||
For example, with `gcc` : `-DLZ4_FAST_DEC_LOOP=1`,
|
||||
and with `make` : `CPPFLAGS+=-DLZ4_FAST_DEC_LOOP=1 make lz4`.
|
||||
|
||||
- `LZ4_DISTANCE_MAX` : control the maximum offset that the compressor will allow.
|
||||
Set to 65535 by default, which is the maximum value supported by lz4 format.
|
||||
Reducing maximum distance will reduce opportunities for LZ4 to find matches,
|
||||
hence will produce a worse compression ratio.
|
||||
However, a smaller max distance can allow compatibility with specific decoders using limited memory budget.
|
||||
This build macro only influences the compressed output of the compressor.
|
||||
|
||||
- `LZ4_DISABLE_DEPRECATE_WARNINGS` : invoking a deprecated function will make the compiler generate a warning.
|
||||
This is meant to invite users to update their source code.
|
||||
Should this be a problem, it's generally possible to make the compiler ignore these warnings,
|
||||
for example with `-Wno-deprecated-declarations` on `gcc`,
|
||||
or `_CRT_SECURE_NO_WARNINGS` for Visual Studio.
|
||||
This build macro offers another project-specific method
|
||||
by defining `LZ4_DISABLE_DEPRECATE_WARNINGS` before including the LZ4 header files.
|
||||
|
||||
- `LZ4_USER_MEMORY_FUNCTIONS` : replace calls to <stdlib>'s `malloc`, `calloc` and `free`
|
||||
by user-defined functions, which must be called `LZ4_malloc()`, `LZ4_calloc()` and `LZ4_free()`.
|
||||
User functions must be available at link time.
|
||||
|
||||
- `LZ4_FORCE_SW_BITCOUNT` : by default, the compression algorithm tries to determine lengths
|
||||
by using bitcount instructions, generally implemented as fast single instructions in many cpus.
|
||||
In case the target cpus doesn't support it, or compiler intrinsic doesn't work, or feature bad performance,
|
||||
it's possible to use an optimized software path instead.
|
||||
This is achieved by setting this build macros .
|
||||
In most cases, it's not expected to be necessary,
|
||||
but it can be legitimately considered for less common platforms.
|
||||
|
||||
- `LZ4_ALIGN_TEST` : alignment test ensures that the memory area
|
||||
passed as argument to become a compression state is suitably aligned.
|
||||
This test can be disabled if it proves flaky, by setting this value to 0.
|
||||
|
||||
|
||||
#### Amalgamation
|
||||
|
||||
lz4 source code can be amalgamated into a single file.
|
||||
One can combine all source code into `lz4_all.c` by using following command:
|
||||
```
|
||||
cat lz4.c lz4hc.c lz4frame.c > lz4_all.c
|
||||
```
|
||||
(`cat` file order is important) then compile `lz4_all.c`.
|
||||
All `*.h` files present in `/lib` remain necessary to compile `lz4_all.c`.
|
||||
|
||||
|
||||
#### Windows : using MinGW+MSYS to create DLL
|
||||
|
||||
DLL can be created using MinGW+MSYS with the `make liblz4` command.
|
||||
This command creates `dll\liblz4.dll` and the import library `dll\liblz4.lib`.
|
||||
To override the `dlltool` command when cross-compiling on Linux, just set the `DLLTOOL` variable. Example of cross compilation on Linux with mingw-w64 64 bits:
|
||||
```
|
||||
make BUILD_STATIC=no CC=x86_64-w64-mingw32-gcc DLLTOOL=x86_64-w64-mingw32-dlltool OS=Windows_NT
|
||||
```
|
||||
The import library is only required with Visual C++.
|
||||
The header files `lz4.h`, `lz4hc.h`, `lz4frame.h` and the dynamic library
|
||||
`dll\liblz4.dll` are required to compile a project using gcc/MinGW.
|
||||
The dynamic library has to be added to linking options.
|
||||
It means that if a project that uses LZ4 consists of a single `test-dll.c`
|
||||
file it should be linked with `dll\liblz4.dll`. For example:
|
||||
```
|
||||
$(CC) $(CFLAGS) -Iinclude/ test-dll.c -o test-dll dll\liblz4.dll
|
||||
```
|
||||
The compiled executable will require LZ4 DLL which is available at `dll\liblz4.dll`.
|
||||
|
||||
|
||||
#### Miscellaneous
|
||||
|
||||
Other files present in the directory are not source code. They are :
|
||||
|
||||
- `LICENSE` : contains the BSD license text
|
||||
- `Makefile` : `make` script to compile and install lz4 library (static and dynamic)
|
||||
- `liblz4.pc.in` : for `pkg-config` (used in `make install`)
|
||||
- `README.md` : this file
|
||||
|
||||
[official interoperable frame format]: ../doc/lz4_Frame_format.md
|
||||
[LZ4 block format]: ../doc/lz4_Block_format.md
|
||||
|
||||
|
||||
#### License
|
||||
|
||||
All source material within __lib__ directory are BSD 2-Clause licensed.
|
||||
See [LICENSE](LICENSE) for details.
|
||||
The license is also reminded at the top of each source file.
|
||||
+2495
File diff suppressed because it is too large
Load Diff
+774
@@ -0,0 +1,774 @@
|
||||
/*
|
||||
* LZ4 - Fast LZ compression algorithm
|
||||
* Header File
|
||||
* Copyright (C) 2011-present, Yann Collet.
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 homepage : http://www.lz4.org
|
||||
- LZ4 source repository : https://github.com/lz4/lz4
|
||||
*/
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef LZ4_H_2983827168210
|
||||
#define LZ4_H_2983827168210
|
||||
|
||||
/* --- Dependency --- */
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
|
||||
/**
|
||||
Introduction
|
||||
|
||||
LZ4 is lossless compression algorithm, providing compression speed >500 MB/s per core,
|
||||
scalable with multi-cores CPU. It features an extremely fast decoder, with speed in
|
||||
multiple GB/s per core, typically reaching RAM speed limits on multi-core systems.
|
||||
|
||||
The LZ4 compression library provides in-memory compression and decompression functions.
|
||||
It gives full buffer control to user.
|
||||
Compression can be done in:
|
||||
- a single step (described as Simple Functions)
|
||||
- a single step, reusing a context (described in Advanced Functions)
|
||||
- unbounded multiple steps (described as Streaming compression)
|
||||
|
||||
lz4.h generates and decodes LZ4-compressed blocks (doc/lz4_Block_format.md).
|
||||
Decompressing such a compressed block requires additional metadata.
|
||||
Exact metadata depends on exact decompression function.
|
||||
For the typical case of LZ4_decompress_safe(),
|
||||
metadata includes block's compressed size, and maximum bound of decompressed size.
|
||||
Each application is free to encode and pass such metadata in whichever way it wants.
|
||||
|
||||
lz4.h only handle blocks, it can not generate Frames.
|
||||
|
||||
Blocks are different from Frames (doc/lz4_Frame_format.md).
|
||||
Frames bundle both blocks and metadata in a specified manner.
|
||||
Embedding metadata is required for compressed data to be self-contained and portable.
|
||||
Frame format is delivered through a companion API, declared in lz4frame.h.
|
||||
The `lz4` CLI can only manage frames.
|
||||
*/
|
||||
|
||||
/*^***************************************************************
|
||||
* Export parameters
|
||||
*****************************************************************/
|
||||
/*
|
||||
* LZ4_DLL_EXPORT :
|
||||
* Enable exporting of functions when building a Windows DLL
|
||||
* LZ4LIB_VISIBILITY :
|
||||
* Control library symbols visibility.
|
||||
*/
|
||||
#ifndef LZ4LIB_VISIBILITY
|
||||
# if defined(__GNUC__) && (__GNUC__ >= 4)
|
||||
# define LZ4LIB_VISIBILITY __attribute__ ((visibility ("default")))
|
||||
# else
|
||||
# define LZ4LIB_VISIBILITY
|
||||
# endif
|
||||
#endif
|
||||
#if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT==1)
|
||||
# define LZ4LIB_API __declspec(dllexport) LZ4LIB_VISIBILITY
|
||||
#elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT==1)
|
||||
# define LZ4LIB_API __declspec(dllimport) LZ4LIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
|
||||
#else
|
||||
# define LZ4LIB_API LZ4LIB_VISIBILITY
|
||||
#endif
|
||||
|
||||
/*------ Version ------*/
|
||||
#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */
|
||||
#define LZ4_VERSION_MINOR 9 /* for new (non-breaking) interface capabilities */
|
||||
#define LZ4_VERSION_RELEASE 3 /* for tweaks, bug-fixes, or development */
|
||||
|
||||
#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE)
|
||||
|
||||
#define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE
|
||||
#define LZ4_QUOTE(str) #str
|
||||
#define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str)
|
||||
#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION)
|
||||
|
||||
LZ4LIB_API int LZ4_versionNumber (void); /**< library version number; useful to check dll version */
|
||||
LZ4LIB_API const char* LZ4_versionString (void); /**< library version string; useful to check dll version */
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Tuning parameter
|
||||
**************************************/
|
||||
/*!
|
||||
* LZ4_MEMORY_USAGE :
|
||||
* Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
|
||||
* Increasing memory usage improves compression ratio.
|
||||
* Reduced memory usage may improve speed, thanks to better cache locality.
|
||||
* Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache
|
||||
*/
|
||||
#ifndef LZ4_MEMORY_USAGE
|
||||
# define LZ4_MEMORY_USAGE 14
|
||||
#endif
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Simple Functions
|
||||
**************************************/
|
||||
/*! LZ4_compress_default() :
|
||||
* Compresses 'srcSize' bytes from buffer 'src'
|
||||
* into already allocated 'dst' buffer of size 'dstCapacity'.
|
||||
* Compression is guaranteed to succeed if 'dstCapacity' >= LZ4_compressBound(srcSize).
|
||||
* It also runs faster, so it's a recommended setting.
|
||||
* If the function cannot compress 'src' into a more limited 'dst' budget,
|
||||
* compression stops *immediately*, and the function result is zero.
|
||||
* In which case, 'dst' content is undefined (invalid).
|
||||
* srcSize : max supported value is LZ4_MAX_INPUT_SIZE.
|
||||
* dstCapacity : size of buffer 'dst' (which must be already allocated)
|
||||
* @return : the number of bytes written into buffer 'dst' (necessarily <= dstCapacity)
|
||||
* or 0 if compression fails
|
||||
* Note : This function is protected against buffer overflow scenarios (never writes outside 'dst' buffer, nor read outside 'source' buffer).
|
||||
*/
|
||||
LZ4LIB_API int LZ4_compress_default(const char* src, char* dst, int srcSize, int dstCapacity);
|
||||
|
||||
/*! LZ4_decompress_safe() :
|
||||
* compressedSize : is the exact complete size of the compressed block.
|
||||
* dstCapacity : is the size of destination buffer (which must be already allocated), presumed an upper bound of decompressed size.
|
||||
* @return : the number of bytes decompressed into destination buffer (necessarily <= dstCapacity)
|
||||
* If destination buffer is not large enough, decoding will stop and output an error code (negative value).
|
||||
* If the source stream is detected malformed, the function will stop decoding and return a negative result.
|
||||
* Note 1 : This function is protected against malicious data packets :
|
||||
* it will never writes outside 'dst' buffer, nor read outside 'source' buffer,
|
||||
* even if the compressed block is maliciously modified to order the decoder to do these actions.
|
||||
* In such case, the decoder stops immediately, and considers the compressed block malformed.
|
||||
* Note 2 : compressedSize and dstCapacity must be provided to the function, the compressed block does not contain them.
|
||||
* The implementation is free to send / store / derive this information in whichever way is most beneficial.
|
||||
* If there is a need for a different format which bundles together both compressed data and its metadata, consider looking at lz4frame.h instead.
|
||||
*/
|
||||
LZ4LIB_API int LZ4_decompress_safe (const char* src, char* dst, int compressedSize, int dstCapacity);
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Advanced Functions
|
||||
**************************************/
|
||||
#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */
|
||||
#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16)
|
||||
|
||||
/*! LZ4_compressBound() :
|
||||
Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible)
|
||||
This function is primarily useful for memory allocation purposes (destination buffer size).
|
||||
Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example).
|
||||
Note that LZ4_compress_default() compresses faster when dstCapacity is >= LZ4_compressBound(srcSize)
|
||||
inputSize : max supported value is LZ4_MAX_INPUT_SIZE
|
||||
return : maximum output size in a "worst case" scenario
|
||||
or 0, if input size is incorrect (too large or negative)
|
||||
*/
|
||||
LZ4LIB_API int LZ4_compressBound(int inputSize);
|
||||
|
||||
/*! LZ4_compress_fast() :
|
||||
Same as LZ4_compress_default(), but allows selection of "acceleration" factor.
|
||||
The larger the acceleration value, the faster the algorithm, but also the lesser the compression.
|
||||
It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed.
|
||||
An acceleration value of "1" is the same as regular LZ4_compress_default()
|
||||
Values <= 0 will be replaced by LZ4_ACCELERATION_DEFAULT (currently == 1, see lz4.c).
|
||||
Values > LZ4_ACCELERATION_MAX will be replaced by LZ4_ACCELERATION_MAX (currently == 65537, see lz4.c).
|
||||
*/
|
||||
LZ4LIB_API int LZ4_compress_fast (const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);
|
||||
|
||||
|
||||
/*! LZ4_compress_fast_extState() :
|
||||
* Same as LZ4_compress_fast(), using an externally allocated memory space for its state.
|
||||
* Use LZ4_sizeofState() to know how much memory must be allocated,
|
||||
* and allocate it on 8-bytes boundaries (using `malloc()` typically).
|
||||
* Then, provide this buffer as `void* state` to compression function.
|
||||
*/
|
||||
LZ4LIB_API int LZ4_sizeofState(void);
|
||||
LZ4LIB_API int LZ4_compress_fast_extState (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);
|
||||
|
||||
|
||||
/*! LZ4_compress_destSize() :
|
||||
* Reverse the logic : compresses as much data as possible from 'src' buffer
|
||||
* into already allocated buffer 'dst', of size >= 'targetDestSize'.
|
||||
* This function either compresses the entire 'src' content into 'dst' if it's large enough,
|
||||
* or fill 'dst' buffer completely with as much data as possible from 'src'.
|
||||
* note: acceleration parameter is fixed to "default".
|
||||
*
|
||||
* *srcSizePtr : will be modified to indicate how many bytes where read from 'src' to fill 'dst'.
|
||||
* New value is necessarily <= input value.
|
||||
* @return : Nb bytes written into 'dst' (necessarily <= targetDestSize)
|
||||
* or 0 if compression fails.
|
||||
*
|
||||
* Note : from v1.8.2 to v1.9.1, this function had a bug (fixed un v1.9.2+):
|
||||
* the produced compressed content could, in specific circumstances,
|
||||
* require to be decompressed into a destination buffer larger
|
||||
* by at least 1 byte than the content to decompress.
|
||||
* If an application uses `LZ4_compress_destSize()`,
|
||||
* it's highly recommended to update liblz4 to v1.9.2 or better.
|
||||
* If this can't be done or ensured,
|
||||
* the receiving decompression function should provide
|
||||
* a dstCapacity which is > decompressedSize, by at least 1 byte.
|
||||
* See https://github.com/lz4/lz4/issues/859 for details
|
||||
*/
|
||||
LZ4LIB_API int LZ4_compress_destSize (const char* src, char* dst, int* srcSizePtr, int targetDstSize);
|
||||
|
||||
|
||||
/*! LZ4_decompress_safe_partial() :
|
||||
* Decompress an LZ4 compressed block, of size 'srcSize' at position 'src',
|
||||
* into destination buffer 'dst' of size 'dstCapacity'.
|
||||
* Up to 'targetOutputSize' bytes will be decoded.
|
||||
* The function stops decoding on reaching this objective.
|
||||
* This can be useful to boost performance
|
||||
* whenever only the beginning of a block is required.
|
||||
*
|
||||
* @return : the number of bytes decoded in `dst` (necessarily <= targetOutputSize)
|
||||
* If source stream is detected malformed, function returns a negative result.
|
||||
*
|
||||
* Note 1 : @return can be < targetOutputSize, if compressed block contains less data.
|
||||
*
|
||||
* Note 2 : targetOutputSize must be <= dstCapacity
|
||||
*
|
||||
* Note 3 : this function effectively stops decoding on reaching targetOutputSize,
|
||||
* so dstCapacity is kind of redundant.
|
||||
* This is because in older versions of this function,
|
||||
* decoding operation would still write complete sequences.
|
||||
* Therefore, there was no guarantee that it would stop writing at exactly targetOutputSize,
|
||||
* it could write more bytes, though only up to dstCapacity.
|
||||
* Some "margin" used to be required for this operation to work properly.
|
||||
* Thankfully, this is no longer necessary.
|
||||
* The function nonetheless keeps the same signature, in an effort to preserve API compatibility.
|
||||
*
|
||||
* Note 4 : If srcSize is the exact size of the block,
|
||||
* then targetOutputSize can be any value,
|
||||
* including larger than the block's decompressed size.
|
||||
* The function will, at most, generate block's decompressed size.
|
||||
*
|
||||
* Note 5 : If srcSize is _larger_ than block's compressed size,
|
||||
* then targetOutputSize **MUST** be <= block's decompressed size.
|
||||
* Otherwise, *silent corruption will occur*.
|
||||
*/
|
||||
LZ4LIB_API int LZ4_decompress_safe_partial (const char* src, char* dst, int srcSize, int targetOutputSize, int dstCapacity);
|
||||
|
||||
|
||||
/*-*********************************************
|
||||
* Streaming Compression Functions
|
||||
***********************************************/
|
||||
typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */
|
||||
|
||||
LZ4LIB_API LZ4_stream_t* LZ4_createStream(void);
|
||||
LZ4LIB_API int LZ4_freeStream (LZ4_stream_t* streamPtr);
|
||||
|
||||
/*! LZ4_resetStream_fast() : v1.9.0+
|
||||
* Use this to prepare an LZ4_stream_t for a new chain of dependent blocks
|
||||
* (e.g., LZ4_compress_fast_continue()).
|
||||
*
|
||||
* An LZ4_stream_t must be initialized once before usage.
|
||||
* This is automatically done when created by LZ4_createStream().
|
||||
* However, should the LZ4_stream_t be simply declared on stack (for example),
|
||||
* it's necessary to initialize it first, using LZ4_initStream().
|
||||
*
|
||||
* After init, start any new stream with LZ4_resetStream_fast().
|
||||
* A same LZ4_stream_t can be re-used multiple times consecutively
|
||||
* and compress multiple streams,
|
||||
* provided that it starts each new stream with LZ4_resetStream_fast().
|
||||
*
|
||||
* LZ4_resetStream_fast() is much faster than LZ4_initStream(),
|
||||
* but is not compatible with memory regions containing garbage data.
|
||||
*
|
||||
* Note: it's only useful to call LZ4_resetStream_fast()
|
||||
* in the context of streaming compression.
|
||||
* The *extState* functions perform their own resets.
|
||||
* Invoking LZ4_resetStream_fast() before is redundant, and even counterproductive.
|
||||
*/
|
||||
LZ4LIB_API void LZ4_resetStream_fast (LZ4_stream_t* streamPtr);
|
||||
|
||||
/*! LZ4_loadDict() :
|
||||
* Use this function to reference a static dictionary into LZ4_stream_t.
|
||||
* The dictionary must remain available during compression.
|
||||
* LZ4_loadDict() triggers a reset, so any previous data will be forgotten.
|
||||
* The same dictionary will have to be loaded on decompression side for successful decoding.
|
||||
* Dictionary are useful for better compression of small data (KB range).
|
||||
* While LZ4 accept any input as dictionary,
|
||||
* results are generally better when using Zstandard's Dictionary Builder.
|
||||
* Loading a size of 0 is allowed, and is the same as reset.
|
||||
* @return : loaded dictionary size, in bytes (necessarily <= 64 KB)
|
||||
*/
|
||||
LZ4LIB_API int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize);
|
||||
|
||||
/*! LZ4_compress_fast_continue() :
|
||||
* Compress 'src' content using data from previously compressed blocks, for better compression ratio.
|
||||
* 'dst' buffer must be already allocated.
|
||||
* If dstCapacity >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster.
|
||||
*
|
||||
* @return : size of compressed block
|
||||
* or 0 if there is an error (typically, cannot fit into 'dst').
|
||||
*
|
||||
* Note 1 : Each invocation to LZ4_compress_fast_continue() generates a new block.
|
||||
* Each block has precise boundaries.
|
||||
* Each block must be decompressed separately, calling LZ4_decompress_*() with relevant metadata.
|
||||
* It's not possible to append blocks together and expect a single invocation of LZ4_decompress_*() to decompress them together.
|
||||
*
|
||||
* Note 2 : The previous 64KB of source data is __assumed__ to remain present, unmodified, at same address in memory !
|
||||
*
|
||||
* Note 3 : When input is structured as a double-buffer, each buffer can have any size, including < 64 KB.
|
||||
* Make sure that buffers are separated, by at least one byte.
|
||||
* This construction ensures that each block only depends on previous block.
|
||||
*
|
||||
* Note 4 : If input buffer is a ring-buffer, it can have any size, including < 64 KB.
|
||||
*
|
||||
* Note 5 : After an error, the stream status is undefined (invalid), it can only be reset or freed.
|
||||
*/
|
||||
LZ4LIB_API int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);
|
||||
|
||||
/*! LZ4_saveDict() :
|
||||
* If last 64KB data cannot be guaranteed to remain available at its current memory location,
|
||||
* save it into a safer place (char* safeBuffer).
|
||||
* This is schematically equivalent to a memcpy() followed by LZ4_loadDict(),
|
||||
* but is much faster, because LZ4_saveDict() doesn't need to rebuild tables.
|
||||
* @return : saved dictionary size in bytes (necessarily <= maxDictSize), or 0 if error.
|
||||
*/
|
||||
LZ4LIB_API int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int maxDictSize);
|
||||
|
||||
|
||||
/*-**********************************************
|
||||
* Streaming Decompression Functions
|
||||
* Bufferless synchronous API
|
||||
************************************************/
|
||||
typedef union LZ4_streamDecode_u LZ4_streamDecode_t; /* tracking context */
|
||||
|
||||
/*! LZ4_createStreamDecode() and LZ4_freeStreamDecode() :
|
||||
* creation / destruction of streaming decompression tracking context.
|
||||
* A tracking context can be re-used multiple times.
|
||||
*/
|
||||
LZ4LIB_API LZ4_streamDecode_t* LZ4_createStreamDecode(void);
|
||||
LZ4LIB_API int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream);
|
||||
|
||||
/*! LZ4_setStreamDecode() :
|
||||
* An LZ4_streamDecode_t context can be allocated once and re-used multiple times.
|
||||
* Use this function to start decompression of a new stream of blocks.
|
||||
* A dictionary can optionally be set. Use NULL or size 0 for a reset order.
|
||||
* Dictionary is presumed stable : it must remain accessible and unmodified during next decompression.
|
||||
* @return : 1 if OK, 0 if error
|
||||
*/
|
||||
LZ4LIB_API int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize);
|
||||
|
||||
/*! LZ4_decoderRingBufferSize() : v1.8.2+
|
||||
* Note : in a ring buffer scenario (optional),
|
||||
* blocks are presumed decompressed next to each other
|
||||
* up to the moment there is not enough remaining space for next block (remainingSize < maxBlockSize),
|
||||
* at which stage it resumes from beginning of ring buffer.
|
||||
* When setting such a ring buffer for streaming decompression,
|
||||
* provides the minimum size of this ring buffer
|
||||
* to be compatible with any source respecting maxBlockSize condition.
|
||||
* @return : minimum ring buffer size,
|
||||
* or 0 if there is an error (invalid maxBlockSize).
|
||||
*/
|
||||
LZ4LIB_API int LZ4_decoderRingBufferSize(int maxBlockSize);
|
||||
#define LZ4_DECODER_RING_BUFFER_SIZE(maxBlockSize) (65536 + 14 + (maxBlockSize)) /* for static allocation; maxBlockSize presumed valid */
|
||||
|
||||
/*! LZ4_decompress_*_continue() :
|
||||
* These decoding functions allow decompression of consecutive blocks in "streaming" mode.
|
||||
* A block is an unsplittable entity, it must be presented entirely to a decompression function.
|
||||
* Decompression functions only accepts one block at a time.
|
||||
* The last 64KB of previously decoded data *must* remain available and unmodified at the memory position where they were decoded.
|
||||
* If less than 64KB of data has been decoded, all the data must be present.
|
||||
*
|
||||
* Special : if decompression side sets a ring buffer, it must respect one of the following conditions :
|
||||
* - Decompression buffer size is _at least_ LZ4_decoderRingBufferSize(maxBlockSize).
|
||||
* maxBlockSize is the maximum size of any single block. It can have any value > 16 bytes.
|
||||
* In which case, encoding and decoding buffers do not need to be synchronized.
|
||||
* Actually, data can be produced by any source compliant with LZ4 format specification, and respecting maxBlockSize.
|
||||
* - Synchronized mode :
|
||||
* Decompression buffer size is _exactly_ the same as compression buffer size,
|
||||
* and follows exactly same update rule (block boundaries at same positions),
|
||||
* and decoding function is provided with exact decompressed size of each block (exception for last block of the stream),
|
||||
* _then_ decoding & encoding ring buffer can have any size, including small ones ( < 64 KB).
|
||||
* - Decompression buffer is larger than encoding buffer, by a minimum of maxBlockSize more bytes.
|
||||
* In which case, encoding and decoding buffers do not need to be synchronized,
|
||||
* and encoding ring buffer can have any size, including small ones ( < 64 KB).
|
||||
*
|
||||
* Whenever these conditions are not possible,
|
||||
* save the last 64KB of decoded data into a safe buffer where it can't be modified during decompression,
|
||||
* then indicate where this data is saved using LZ4_setStreamDecode(), before decompressing next block.
|
||||
*/
|
||||
LZ4LIB_API int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int srcSize, int dstCapacity);
|
||||
|
||||
|
||||
/*! LZ4_decompress_*_usingDict() :
|
||||
* These decoding functions work the same as
|
||||
* a combination of LZ4_setStreamDecode() followed by LZ4_decompress_*_continue()
|
||||
* They are stand-alone, and don't need an LZ4_streamDecode_t structure.
|
||||
* Dictionary is presumed stable : it must remain accessible and unmodified during decompression.
|
||||
* Performance tip : Decompression speed can be substantially increased
|
||||
* when dst == dictStart + dictSize.
|
||||
*/
|
||||
LZ4LIB_API int LZ4_decompress_safe_usingDict (const char* src, char* dst, int srcSize, int dstCapcity, const char* dictStart, int dictSize);
|
||||
|
||||
#endif /* LZ4_H_2983827168210 */
|
||||
|
||||
|
||||
/*^*************************************
|
||||
* !!!!!! STATIC LINKING ONLY !!!!!!
|
||||
***************************************/
|
||||
|
||||
/*-****************************************************************************
|
||||
* Experimental section
|
||||
*
|
||||
* Symbols declared in this section must be considered unstable. Their
|
||||
* signatures or semantics may change, or they may be removed altogether in the
|
||||
* future. They are therefore only safe to depend on when the caller is
|
||||
* statically linked against the library.
|
||||
*
|
||||
* To protect against unsafe usage, not only are the declarations guarded,
|
||||
* the definitions are hidden by default
|
||||
* when building LZ4 as a shared/dynamic library.
|
||||
*
|
||||
* In order to access these declarations,
|
||||
* define LZ4_STATIC_LINKING_ONLY in your application
|
||||
* before including LZ4's headers.
|
||||
*
|
||||
* In order to make their implementations accessible dynamically, you must
|
||||
* define LZ4_PUBLISH_STATIC_FUNCTIONS when building the LZ4 library.
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef LZ4_STATIC_LINKING_ONLY
|
||||
|
||||
#ifndef LZ4_STATIC_3504398509
|
||||
#define LZ4_STATIC_3504398509
|
||||
|
||||
#ifdef LZ4_PUBLISH_STATIC_FUNCTIONS
|
||||
#define LZ4LIB_STATIC_API LZ4LIB_API
|
||||
#else
|
||||
#define LZ4LIB_STATIC_API
|
||||
#endif
|
||||
|
||||
|
||||
/*! LZ4_compress_fast_extState_fastReset() :
|
||||
* A variant of LZ4_compress_fast_extState().
|
||||
*
|
||||
* Using this variant avoids an expensive initialization step.
|
||||
* It is only safe to call if the state buffer is known to be correctly initialized already
|
||||
* (see above comment on LZ4_resetStream_fast() for a definition of "correctly initialized").
|
||||
* From a high level, the difference is that
|
||||
* this function initializes the provided state with a call to something like LZ4_resetStream_fast()
|
||||
* while LZ4_compress_fast_extState() starts with a call to LZ4_resetStream().
|
||||
*/
|
||||
LZ4LIB_STATIC_API int LZ4_compress_fast_extState_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);
|
||||
|
||||
/*! LZ4_attach_dictionary() :
|
||||
* This is an experimental API that allows
|
||||
* efficient use of a static dictionary many times.
|
||||
*
|
||||
* Rather than re-loading the dictionary buffer into a working context before
|
||||
* each compression, or copying a pre-loaded dictionary's LZ4_stream_t into a
|
||||
* working LZ4_stream_t, this function introduces a no-copy setup mechanism,
|
||||
* in which the working stream references the dictionary stream in-place.
|
||||
*
|
||||
* Several assumptions are made about the state of the dictionary stream.
|
||||
* Currently, only streams which have been prepared by LZ4_loadDict() should
|
||||
* be expected to work.
|
||||
*
|
||||
* Alternatively, the provided dictionaryStream may be NULL,
|
||||
* in which case any existing dictionary stream is unset.
|
||||
*
|
||||
* If a dictionary is provided, it replaces any pre-existing stream history.
|
||||
* The dictionary contents are the only history that can be referenced and
|
||||
* logically immediately precede the data compressed in the first subsequent
|
||||
* compression call.
|
||||
*
|
||||
* The dictionary will only remain attached to the working stream through the
|
||||
* first compression call, at the end of which it is cleared. The dictionary
|
||||
* stream (and source buffer) must remain in-place / accessible / unchanged
|
||||
* through the completion of the first compression call on the stream.
|
||||
*/
|
||||
LZ4LIB_STATIC_API void LZ4_attach_dictionary(LZ4_stream_t* workingStream, const LZ4_stream_t* dictionaryStream);
|
||||
|
||||
|
||||
/*! In-place compression and decompression
|
||||
*
|
||||
* It's possible to have input and output sharing the same buffer,
|
||||
* for highly contrained memory environments.
|
||||
* In both cases, it requires input to lay at the end of the buffer,
|
||||
* and decompression to start at beginning of the buffer.
|
||||
* Buffer size must feature some margin, hence be larger than final size.
|
||||
*
|
||||
* |<------------------------buffer--------------------------------->|
|
||||
* |<-----------compressed data--------->|
|
||||
* |<-----------decompressed size------------------>|
|
||||
* |<----margin---->|
|
||||
*
|
||||
* This technique is more useful for decompression,
|
||||
* since decompressed size is typically larger,
|
||||
* and margin is short.
|
||||
*
|
||||
* In-place decompression will work inside any buffer
|
||||
* which size is >= LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(decompressedSize).
|
||||
* This presumes that decompressedSize > compressedSize.
|
||||
* Otherwise, it means compression actually expanded data,
|
||||
* and it would be more efficient to store such data with a flag indicating it's not compressed.
|
||||
* This can happen when data is not compressible (already compressed, or encrypted).
|
||||
*
|
||||
* For in-place compression, margin is larger, as it must be able to cope with both
|
||||
* history preservation, requiring input data to remain unmodified up to LZ4_DISTANCE_MAX,
|
||||
* and data expansion, which can happen when input is not compressible.
|
||||
* As a consequence, buffer size requirements are much higher,
|
||||
* and memory savings offered by in-place compression are more limited.
|
||||
*
|
||||
* There are ways to limit this cost for compression :
|
||||
* - Reduce history size, by modifying LZ4_DISTANCE_MAX.
|
||||
* Note that it is a compile-time constant, so all compressions will apply this limit.
|
||||
* Lower values will reduce compression ratio, except when input_size < LZ4_DISTANCE_MAX,
|
||||
* so it's a reasonable trick when inputs are known to be small.
|
||||
* - Require the compressor to deliver a "maximum compressed size".
|
||||
* This is the `dstCapacity` parameter in `LZ4_compress*()`.
|
||||
* When this size is < LZ4_COMPRESSBOUND(inputSize), then compression can fail,
|
||||
* in which case, the return code will be 0 (zero).
|
||||
* The caller must be ready for these cases to happen,
|
||||
* and typically design a backup scheme to send data uncompressed.
|
||||
* The combination of both techniques can significantly reduce
|
||||
* the amount of margin required for in-place compression.
|
||||
*
|
||||
* In-place compression can work in any buffer
|
||||
* which size is >= (maxCompressedSize)
|
||||
* with maxCompressedSize == LZ4_COMPRESSBOUND(srcSize) for guaranteed compression success.
|
||||
* LZ4_COMPRESS_INPLACE_BUFFER_SIZE() depends on both maxCompressedSize and LZ4_DISTANCE_MAX,
|
||||
* so it's possible to reduce memory requirements by playing with them.
|
||||
*/
|
||||
|
||||
#define LZ4_DECOMPRESS_INPLACE_MARGIN(compressedSize) (((compressedSize) >> 8) + 32)
|
||||
#define LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(decompressedSize) ((decompressedSize) + LZ4_DECOMPRESS_INPLACE_MARGIN(decompressedSize)) /**< note: presumes that compressedSize < decompressedSize. note2: margin is overestimated a bit, since it could use compressedSize instead */
|
||||
|
||||
#ifndef LZ4_DISTANCE_MAX /* history window size; can be user-defined at compile time */
|
||||
# define LZ4_DISTANCE_MAX 65535 /* set to maximum value by default */
|
||||
#endif
|
||||
|
||||
#define LZ4_COMPRESS_INPLACE_MARGIN (LZ4_DISTANCE_MAX + 32) /* LZ4_DISTANCE_MAX can be safely replaced by srcSize when it's smaller */
|
||||
#define LZ4_COMPRESS_INPLACE_BUFFER_SIZE(maxCompressedSize) ((maxCompressedSize) + LZ4_COMPRESS_INPLACE_MARGIN) /**< maxCompressedSize is generally LZ4_COMPRESSBOUND(inputSize), but can be set to any lower value, with the risk that compression can fail (return code 0(zero)) */
|
||||
|
||||
#endif /* LZ4_STATIC_3504398509 */
|
||||
#endif /* LZ4_STATIC_LINKING_ONLY */
|
||||
|
||||
|
||||
|
||||
#ifndef LZ4_H_98237428734687
|
||||
#define LZ4_H_98237428734687
|
||||
|
||||
/*-************************************************************
|
||||
* Private Definitions
|
||||
**************************************************************
|
||||
* Do not use these definitions directly.
|
||||
* They are only exposed to allow static allocation of `LZ4_stream_t` and `LZ4_streamDecode_t`.
|
||||
* Accessing members will expose user code to API and/or ABI break in future versions of the library.
|
||||
**************************************************************/
|
||||
#define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2)
|
||||
#define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE)
|
||||
#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */
|
||||
|
||||
#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
|
||||
# include <stdint.h>
|
||||
typedef int8_t LZ4_i8;
|
||||
typedef uint8_t LZ4_byte;
|
||||
typedef uint16_t LZ4_u16;
|
||||
typedef uint32_t LZ4_u32;
|
||||
#else
|
||||
typedef signed char LZ4_i8;
|
||||
typedef unsigned char LZ4_byte;
|
||||
typedef unsigned short LZ4_u16;
|
||||
typedef unsigned int LZ4_u32;
|
||||
#endif
|
||||
|
||||
typedef struct LZ4_stream_t_internal LZ4_stream_t_internal;
|
||||
struct LZ4_stream_t_internal {
|
||||
LZ4_u32 hashTable[LZ4_HASH_SIZE_U32];
|
||||
LZ4_u32 currentOffset;
|
||||
LZ4_u32 tableType;
|
||||
const LZ4_byte* dictionary;
|
||||
const LZ4_stream_t_internal* dictCtx;
|
||||
LZ4_u32 dictSize;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const LZ4_byte* externalDict;
|
||||
size_t extDictSize;
|
||||
const LZ4_byte* prefixEnd;
|
||||
size_t prefixSize;
|
||||
} LZ4_streamDecode_t_internal;
|
||||
|
||||
|
||||
/*! LZ4_stream_t :
|
||||
* Do not use below internal definitions directly !
|
||||
* Declare or allocate an LZ4_stream_t instead.
|
||||
* LZ4_stream_t can also be created using LZ4_createStream(), which is recommended.
|
||||
* The structure definition can be convenient for static allocation
|
||||
* (on stack, or as part of larger structure).
|
||||
* Init this structure with LZ4_initStream() before first use.
|
||||
* note : only use this definition in association with static linking !
|
||||
* this definition is not API/ABI safe, and may change in future versions.
|
||||
*/
|
||||
#define LZ4_STREAMSIZE 16416 /* static size, for inter-version compatibility */
|
||||
#define LZ4_STREAMSIZE_VOIDP (LZ4_STREAMSIZE / sizeof(void*))
|
||||
union LZ4_stream_u {
|
||||
void* table[LZ4_STREAMSIZE_VOIDP];
|
||||
LZ4_stream_t_internal internal_donotuse;
|
||||
}; /* previously typedef'd to LZ4_stream_t */
|
||||
|
||||
|
||||
/*! LZ4_initStream() : v1.9.0+
|
||||
* An LZ4_stream_t structure must be initialized at least once.
|
||||
* This is automatically done when invoking LZ4_createStream(),
|
||||
* but it's not when the structure is simply declared on stack (for example).
|
||||
*
|
||||
* Use LZ4_initStream() to properly initialize a newly declared LZ4_stream_t.
|
||||
* It can also initialize any arbitrary buffer of sufficient size,
|
||||
* and will @return a pointer of proper type upon initialization.
|
||||
*
|
||||
* Note : initialization fails if size and alignment conditions are not respected.
|
||||
* In which case, the function will @return NULL.
|
||||
* Note2: An LZ4_stream_t structure guarantees correct alignment and size.
|
||||
* Note3: Before v1.9.0, use LZ4_resetStream() instead
|
||||
*/
|
||||
LZ4LIB_API LZ4_stream_t* LZ4_initStream (void* buffer, size_t size);
|
||||
|
||||
|
||||
/*! LZ4_streamDecode_t :
|
||||
* information structure to track an LZ4 stream during decompression.
|
||||
* init this structure using LZ4_setStreamDecode() before first use.
|
||||
* note : only use in association with static linking !
|
||||
* this definition is not API/ABI safe,
|
||||
* and may change in a future version !
|
||||
*/
|
||||
#define LZ4_STREAMDECODESIZE_U64 (4 + ((sizeof(void*)==16) ? 2 : 0) /*AS-400*/ )
|
||||
#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long))
|
||||
union LZ4_streamDecode_u {
|
||||
unsigned long long table[LZ4_STREAMDECODESIZE_U64];
|
||||
LZ4_streamDecode_t_internal internal_donotuse;
|
||||
} ; /* previously typedef'd to LZ4_streamDecode_t */
|
||||
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Obsolete Functions
|
||||
**************************************/
|
||||
|
||||
/*! Deprecation warnings
|
||||
*
|
||||
* Deprecated functions make the compiler generate a warning when invoked.
|
||||
* This is meant to invite users to update their source code.
|
||||
* Should deprecation warnings be a problem, it is generally possible to disable them,
|
||||
* typically with -Wno-deprecated-declarations for gcc
|
||||
* or _CRT_SECURE_NO_WARNINGS in Visual.
|
||||
*
|
||||
* Another method is to define LZ4_DISABLE_DEPRECATE_WARNINGS
|
||||
* before including the header file.
|
||||
*/
|
||||
#ifdef LZ4_DISABLE_DEPRECATE_WARNINGS
|
||||
# define LZ4_DEPRECATED(message) /* disable deprecation warnings */
|
||||
#else
|
||||
# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */
|
||||
# define LZ4_DEPRECATED(message) [[deprecated(message)]]
|
||||
# elif defined(_MSC_VER)
|
||||
# define LZ4_DEPRECATED(message) __declspec(deprecated(message))
|
||||
# elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 45))
|
||||
# define LZ4_DEPRECATED(message) __attribute__((deprecated(message)))
|
||||
# elif defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 31)
|
||||
# define LZ4_DEPRECATED(message) __attribute__((deprecated))
|
||||
# else
|
||||
# pragma message("WARNING: LZ4_DEPRECATED needs custom implementation for this compiler")
|
||||
# define LZ4_DEPRECATED(message) /* disabled */
|
||||
# endif
|
||||
#endif /* LZ4_DISABLE_DEPRECATE_WARNINGS */
|
||||
|
||||
/*! Obsolete compression functions (since v1.7.3) */
|
||||
LZ4_DEPRECATED("use LZ4_compress_default() instead") LZ4LIB_API int LZ4_compress (const char* src, char* dest, int srcSize);
|
||||
LZ4_DEPRECATED("use LZ4_compress_default() instead") LZ4LIB_API int LZ4_compress_limitedOutput (const char* src, char* dest, int srcSize, int maxOutputSize);
|
||||
LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") LZ4LIB_API int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize);
|
||||
LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") LZ4LIB_API int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);
|
||||
LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") LZ4LIB_API int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize);
|
||||
LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") LZ4LIB_API int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize);
|
||||
|
||||
/*! Obsolete decompression functions (since v1.8.0) */
|
||||
LZ4_DEPRECATED("use LZ4_decompress_fast() instead") LZ4LIB_API int LZ4_uncompress (const char* source, char* dest, int outputSize);
|
||||
LZ4_DEPRECATED("use LZ4_decompress_safe() instead") LZ4LIB_API int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize);
|
||||
|
||||
/* Obsolete streaming functions (since v1.7.0)
|
||||
* degraded functionality; do not use!
|
||||
*
|
||||
* In order to perform streaming compression, these functions depended on data
|
||||
* that is no longer tracked in the state. They have been preserved as well as
|
||||
* possible: using them will still produce a correct output. However, they don't
|
||||
* actually retain any history between compression calls. The compression ratio
|
||||
* achieved will therefore be no better than compressing each chunk
|
||||
* independently.
|
||||
*/
|
||||
LZ4_DEPRECATED("Use LZ4_createStream() instead") LZ4LIB_API void* LZ4_create (char* inputBuffer);
|
||||
LZ4_DEPRECATED("Use LZ4_createStream() instead") LZ4LIB_API int LZ4_sizeofStreamState(void);
|
||||
LZ4_DEPRECATED("Use LZ4_resetStream() instead") LZ4LIB_API int LZ4_resetStreamState(void* state, char* inputBuffer);
|
||||
LZ4_DEPRECATED("Use LZ4_saveDict() instead") LZ4LIB_API char* LZ4_slideInputBuffer (void* state);
|
||||
|
||||
/*! Obsolete streaming decoding functions (since v1.7.0) */
|
||||
LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") LZ4LIB_API int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize);
|
||||
LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") LZ4LIB_API int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize);
|
||||
|
||||
/*! Obsolete LZ4_decompress_fast variants (since v1.9.0) :
|
||||
* These functions used to be faster than LZ4_decompress_safe(),
|
||||
* but this is no longer the case. They are now slower.
|
||||
* This is because LZ4_decompress_fast() doesn't know the input size,
|
||||
* and therefore must progress more cautiously into the input buffer to not read beyond the end of block.
|
||||
* On top of that `LZ4_decompress_fast()` is not protected vs malformed or malicious inputs, making it a security liability.
|
||||
* As a consequence, LZ4_decompress_fast() is strongly discouraged, and deprecated.
|
||||
*
|
||||
* The last remaining LZ4_decompress_fast() specificity is that
|
||||
* it can decompress a block without knowing its compressed size.
|
||||
* Such functionality can be achieved in a more secure manner
|
||||
* by employing LZ4_decompress_safe_partial().
|
||||
*
|
||||
* Parameters:
|
||||
* originalSize : is the uncompressed size to regenerate.
|
||||
* `dst` must be already allocated, its size must be >= 'originalSize' bytes.
|
||||
* @return : number of bytes read from source buffer (== compressed size).
|
||||
* The function expects to finish at block's end exactly.
|
||||
* If the source stream is detected malformed, the function stops decoding and returns a negative result.
|
||||
* note : LZ4_decompress_fast*() requires originalSize. Thanks to this information, it never writes past the output buffer.
|
||||
* However, since it doesn't know its 'src' size, it may read an unknown amount of input, past input buffer bounds.
|
||||
* Also, since match offsets are not validated, match reads from 'src' may underflow too.
|
||||
* These issues never happen if input (compressed) data is correct.
|
||||
* But they may happen if input data is invalid (error or intentional tampering).
|
||||
* As a consequence, use these functions in trusted environments with trusted data **only**.
|
||||
*/
|
||||
LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe() instead")
|
||||
LZ4LIB_API int LZ4_decompress_fast (const char* src, char* dst, int originalSize);
|
||||
LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_continue() instead")
|
||||
LZ4LIB_API int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int originalSize);
|
||||
LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_usingDict() instead")
|
||||
LZ4LIB_API int LZ4_decompress_fast_usingDict (const char* src, char* dst, int originalSize, const char* dictStart, int dictSize);
|
||||
|
||||
/*! LZ4_resetStream() :
|
||||
* An LZ4_stream_t structure must be initialized at least once.
|
||||
* This is done with LZ4_initStream(), or LZ4_resetStream().
|
||||
* Consider switching to LZ4_initStream(),
|
||||
* invoking LZ4_resetStream() will trigger deprecation warnings in the future.
|
||||
*/
|
||||
LZ4LIB_API void LZ4_resetStream (LZ4_stream_t* streamPtr);
|
||||
|
||||
|
||||
#endif /* LZ4_H_98237428734687 */
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
+1
Submodule radio/src/thirdparty/libopenui/thirdparty/stb added at 7cce4c3ad9
+213
@@ -0,0 +1,213 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import argparse
|
||||
from PIL import Image
|
||||
|
||||
# LZ4 compression
|
||||
import lz4.block
|
||||
|
||||
class RawMixin:
|
||||
def encode_byte(self, byte):
|
||||
self.write(byte)
|
||||
|
||||
def encode_end(self):
|
||||
pass
|
||||
|
||||
class RleMixin:
|
||||
RLE_BYTE = 0
|
||||
RLE_SEQ = 1
|
||||
|
||||
def __init__(self):
|
||||
self.state = self.RLE_BYTE
|
||||
self.count = 0
|
||||
self.prev_byte = None
|
||||
|
||||
def eq_prev_byte(self, byte):
|
||||
if self.prev_byte is None:
|
||||
return False
|
||||
return byte == self.prev_byte
|
||||
|
||||
def encode_byte(self, byte):
|
||||
if self.state == self.RLE_BYTE:
|
||||
self.write(byte)
|
||||
if self.eq_prev_byte(byte):
|
||||
self.state = self.RLE_SEQ
|
||||
self.count = 0
|
||||
else:
|
||||
self.prev_byte = byte
|
||||
elif self.state == self.RLE_SEQ:
|
||||
if self.eq_prev_byte(byte):
|
||||
self.count += 1
|
||||
if self.count == 255:
|
||||
self.write(self.count)
|
||||
self.prev_byte = None
|
||||
self.state = self.RLE_BYTE
|
||||
else:
|
||||
self.write(self.count)
|
||||
self.write(byte)
|
||||
self.prev_byte = byte
|
||||
self.state = self.RLE_BYTE
|
||||
|
||||
def encode_end(self):
|
||||
if self.state == self.RLE_SEQ:
|
||||
self.write(self.count)
|
||||
|
||||
class Lz4Mixin:
|
||||
|
||||
def __init__(self):
|
||||
self.buffer = []
|
||||
|
||||
def encode_byte(self,byte):
|
||||
self.buffer.append(byte)
|
||||
|
||||
def encode_end(self):
|
||||
compressed_data = lz4.block.compress(bytes(self.buffer), compression=12, mode='high_compression', store_size=False)
|
||||
data_len = len(compressed_data).to_bytes(4, byteorder='little')
|
||||
for b in data_len:
|
||||
self.write(b)
|
||||
for b in compressed_data:
|
||||
self.write(b)
|
||||
|
||||
class ImageEncoder:
|
||||
def __init__(self, filename, size_format, reverse=False):
|
||||
self.f = open(filename, "w")
|
||||
self.size_format = size_format
|
||||
self.reverse = reverse
|
||||
|
||||
def write(self, value):
|
||||
if isinstance(value, bytes):
|
||||
value = int.from_bytes(value, 'little')
|
||||
self.f.write("0x%02x," % value)
|
||||
|
||||
def write_size(self, width, height):
|
||||
if self.size_format == 2:
|
||||
self.f.write("%d,%d,%d,%d,\n" % (width % 256, width // 256, height % 256, height // 256))
|
||||
else:
|
||||
self.f.write("%d,%d,\n" % (width, height))
|
||||
|
||||
def encode_1bit(self, image, rows):
|
||||
image = image.convert(mode='1')
|
||||
width, height = image.size
|
||||
self.write_size(width, height // rows)
|
||||
for y in range(0, height, 8):
|
||||
for x in range(width):
|
||||
value = 0
|
||||
for z in range(8):
|
||||
if y + z < height:
|
||||
if image.format == "XBM":
|
||||
if image.getpixel((x, y + z)) > 0:
|
||||
value += 1 << z
|
||||
else:
|
||||
if image.getpixel((x, y + z)) == 0:
|
||||
value += 1 << z
|
||||
self.encode_byte(value)
|
||||
self.f.write("\n")
|
||||
self.encode_end()
|
||||
|
||||
def encode_4bits(self, image):
|
||||
image = image.convert(mode='L')
|
||||
width, height = image.size
|
||||
self.write_size(width, height)
|
||||
for y in range(0, height, 2):
|
||||
for x in range(width):
|
||||
value = 0xFF
|
||||
gray1 = self.get_pixel(image, x, y)
|
||||
if y + 1 < height:
|
||||
gray2 = self.get_pixel(image, x, y + 1)
|
||||
else:
|
||||
gray2 = 255
|
||||
for i in range(4):
|
||||
if gray1 & (1 << (4 + i)):
|
||||
value -= 1 << i
|
||||
if gray2 & (1 << (4 + i)):
|
||||
value -= 1 << (4 + i)
|
||||
self.encode_byte(value)
|
||||
self.f.write("\n")
|
||||
self.encode_end()
|
||||
|
||||
def encode_8bits(self, image):
|
||||
image = image.convert(mode='L')
|
||||
width, height = image.size
|
||||
self.write_size(width, height)
|
||||
for y in range(height):
|
||||
for x in range(width):
|
||||
value = self.get_pixel(image, x, y)
|
||||
value = 0xFF - value
|
||||
self.encode_byte(value)
|
||||
self.encode_end()
|
||||
|
||||
def encode_5_6_5(self, image):
|
||||
width, height = image.size
|
||||
self.write_size(width, height)
|
||||
for y in range(height):
|
||||
for x in range(width):
|
||||
pixel = self.get_pixel(image, x, y)
|
||||
val = ((pixel[0] >> 3) << 11) + ((pixel[1] >> 2) << 5) + ((pixel[2] >> 3) << 0)
|
||||
self.encode_byte(val & 255)
|
||||
self.encode_byte(val >> 8)
|
||||
self.encode_end()
|
||||
|
||||
def encode_4_4_4_4(self, image):
|
||||
width, height = image.size
|
||||
self.write_size(width, height)
|
||||
for y in range(height):
|
||||
for x in range(width):
|
||||
pixel = self.get_pixel(image, x, y)
|
||||
val = ((pixel[3] // 16) << 12) + ((pixel[0] // 16) << 8) + ((pixel[1] // 16) << 4) + ((pixel[2] // 16) << 0)
|
||||
self.encode_byte(val & 255)
|
||||
self.encode_byte(val >> 8)
|
||||
self.encode_end()
|
||||
|
||||
def get_pixel(self, image, x, y):
|
||||
if self.reverse:
|
||||
return image.getpixel((image.width - x - 1, image.height - y - 1))
|
||||
else:
|
||||
return image.getpixel((x, y))
|
||||
|
||||
@staticmethod
|
||||
def create(filename, size_format=1, reverse=False, encode_mixin=RawMixin):
|
||||
class ResultClass(ImageEncoder, encode_mixin):
|
||||
def __init__(self, *args, **kwargs):
|
||||
ImageEncoder.__init__(self, *args, **kwargs)
|
||||
encode_mixin.__init__(self)
|
||||
return ResultClass(filename, size_format, reverse)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Bitmaps encoder')
|
||||
parser.add_argument('input', action="store", help="Input file name")
|
||||
parser.add_argument('output', action="store", help="Output file name")
|
||||
parser.add_argument('--format', action="store", help="Output format")
|
||||
parser.add_argument("--reverse", help="Invert pixels order", action="store_true")
|
||||
parser.add_argument("--rle", help="Enable RLE compression", action="store_true")
|
||||
parser.add_argument("--lz4", help="Enable RLE compression", action="store_true")
|
||||
parser.add_argument("--rows", help="Image rows count (for 1bit format)", type=int, default=1)
|
||||
parser.add_argument("--size-format", help="Header image size format (1 or 2 bytes)", type=int, default=1)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
image = Image.open(args.input)
|
||||
output = args.output
|
||||
|
||||
byte_encoder = RawMixin
|
||||
if args.rle:
|
||||
byte_encoder = RleMixin
|
||||
if args.lz4:
|
||||
byte_encoder = Lz4Mixin
|
||||
|
||||
encoder = ImageEncoder.create(output, args.size_format, args.reverse, byte_encoder)
|
||||
|
||||
if args.format == "1bit":
|
||||
encoder.encode_1bit(image, args.rows)
|
||||
elif args.format == "4bits":
|
||||
encoder.encode_4bits(image)
|
||||
elif args.format == "8bits":
|
||||
encoder.encode_8bits(image)
|
||||
elif args.format == "4/4/4/4":
|
||||
encoder.encode_4_4_4_4(image)
|
||||
elif args.format == "5/6/5":
|
||||
encoder.encode_5_6_5(image)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user