message: XListbox with dynamic updates (insert/delete) issue 205

diff:
//<File !Start!>
// FILE: [ex31_bld_listbox.ino]
-// Created by GUIslice Builder version: [0.13.0]
+// Created by GUIslice Builder version: [0.14.b005]
//
-// GUIslice Builder Generated File
+// GUIslice Builder Generated GUI Framework File
//
// For the latest guides, updates and support view:
// https://github.com/ImpulseAdventure/GUIslice
//
// - Example 31 (Arduino): Listbox + Scrollbar
// - Demonstrates Listbox control (single-column) with scrollbar
+// Usage of InsertItemAt and DeleteItemAt for List.
// - Shows callback notifications for Listbox
// - Provide example of additional Adafruit-GFX fonts
// (see USE_EXTRA_FONTS)
// Note that font files are located within the Adafruit-GFX library folder:
// ------------------------------------------------
//<Fonts !Start!>
+#if defined(DRV_DISP_TFT_ESPI)
+ #error Builder config "Edit->Options->General->Target Platform" should be "arduino TFT_eSPI"
+#endif
#include <Adafruit_GFX.h>
// Note that these files are located within the Adafruit-GFX library folder:
#include "Fonts/FreeMono9pt7b.h"
// Enumerations for pages, elements, fonts, images
// ------------------------------------------------
//<Enum !Start!>
-enum {E_PG_MAIN};
-enum {E_BTN_OK,E_LBL_COUNTRYCD,E_LBL_TITLE,E_LISTBOX,E_LISTSCROLL1
+enum {E_PG_MAIN,E_PG_WARNING};
+enum {E_BTN_ADD,E_BTN_DEL,E_BTN_OK,E_ELEM_BOX1,E_ELEM_TEXT4
+ ,E_ELEM_TEXT5,E_LBL_COUNTRYCD,E_LBL_TITLE,E_LISTBOX,E_LISTSCROLL1
,E_TXT_COUNTRY_CODE};
// Must use separate enum for fonts with MAX_FONT at end to use gslc_FontSet.
-enum {E_FONT_MONO9,E_FONT_SANS9,MAX_FONT};
+enum {E_BUILTIN_TXT10,E_BUILTIN_TXT5,E_FREE_MONO9,E_FREE_SANS9,MAX_FONT};
//<Enum !End!>
// ------------------------------------------------
@@ -74,10 +79,13 @@ enum {E_FONT_MONO9,E_FONT_SANS9,MAX_FONT};
// Define the maximum number of elements and pages
// ------------------------------------------------
//<ElementDefines !Start!>
-#define MAX_PAGE 1
+#define MAX_PAGE 2
-#define MAX_ELEM_PG_MAIN 7 // # Elems total on page
+#define MAX_ELEM_PG_MAIN 8 // # Elems total on page
#define MAX_ELEM_PG_MAIN_RAM MAX_ELEM_PG_MAIN // # Elems in RAM
+
+#define MAX_ELEM_PG_WARNING 4 // # Elems total on page
+#define MAX_ELEM_PG_WARNING_RAM MAX_ELEM_PG_WARNING // # Elems in RAM
//<ElementDefines !End!>
// ------------------------------------------------
@@ -91,12 +99,14 @@ gslc_tsPage m_asPage[MAX_PAGE];
//<GUI_Extra_Elements !Start!>
gslc_tsElem m_asPage1Elem[MAX_ELEM_PG_MAIN_RAM];
gslc_tsElemRef m_asPage1ElemRef[MAX_ELEM_PG_MAIN];
+gslc_tsElem m_asPopup1Elem[MAX_ELEM_PG_WARNING_RAM];
+gslc_tsElemRef m_asPopup1ElemRef[MAX_ELEM_PG_WARNING];
gslc_tsXListbox m_sListbox1;
// - Note that XLISTBOX_BUF_OH_R is extra required per item
-char m_acListboxBuf1[81 + XLISTBOX_BUF_OH_R];
+char m_acListboxBuf1[100 + XLISTBOX_BUF_OH_R];
gslc_tsXSlider m_sListScroll1;
-#define MAX_STR 100
+#define MAX_STR 20
//<GUI_Extra_Elements !End!>
@@ -104,9 +114,16 @@ gslc_tsXSlider m_sListScroll1;
// Program Globals
// ------------------------------------------------
bool m_bQuit = false;
+char m_EmptyStr[] = "\0";
+char* m_pEmptyStr = (char*)&m_EmptyStr;
+char m_NewCountry[] = "New Country";
+char* m_pNewCountry = (char*)&m_NewCountry;
+int16_t m_nNumNewCountry = 0;
+char m_NewCode[10];
+
+#define COUNTRY_CNT 13
-#define COUNTRY_CNT 12
-char m_astrCountryCodes[COUNTRY_CNT][3] = {
+char m_CountryCodes[COUNTRY_CNT][4] = {
"US",
"BR",
"CA",
@@ -118,14 +135,46 @@ char m_astrCountryCodes[COUNTRY_CNT][3] = {
"MX",
"PE",
"UK",
- "VN"
+ "VN",
+ "NEW"
+};
+
+char m_CountryNames[COUNTRY_CNT][15] = {
+ "USA",
+ "Brazil",
+ "Canada",
+ "Denmark",
+ "Germany",
+ "France",
+ "India",
+ "Japan",
+ "Mexico",
+ "Peru",
+ "England",
+ "Vietnam",
+ "New Country"
};
+char* searchCountryCode(char* countryName) {
+
+ for(int i=0; i<COUNTRY_CNT-1; i++) {
+ if (strcmp(countryName,(char*)&m_CountryNames[i]) == 0) {
+ return m_CountryCodes[i];
+ }
+ }
+ // take care of case where we have "New Country1", "NewCountry2" and so on...
+ if (strncmp(countryName,m_pNewCountry,11) == 0) {
+ sprintf(m_NewCode,"%s%s","NEW",(char*)&countryName[11]);
+ return m_NewCode;
+ }
+ return m_pEmptyStr;
+}
+
+
// Save some element references for direct access
//<Save_References !Start!>
gslc_tsElemRef* m_pElemListbox = NULL;
-gslc_tsElemRef* m_pElemOK = NULL;
gslc_tsElemRef* m_pElemSel = NULL;
gslc_tsElemRef* m_pListSlider1 = NULL;
//<Save_References !End!>
@@ -142,15 +191,35 @@ bool CbBtnCommon(void* pvGui,void *pvElemRef,gslc_teTouch eTouch,int16_t nX,int1
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
gslc_tsElem* pElem = gslc_GetElemFromRef(&m_gui,pElemRef);
+ char acTxt[MAX_STR+1];
+ int16_t nSelId;
+
if ( eTouch == GSLC_TOUCH_UP_IN ) {
// From the element's ID we can determine which button was pressed.
switch (pElem->nId) {
//<Button Enums !Start!>
-
+ case E_BTN_ADD:
+ sprintf(acTxt,"%s%d",m_pNewCountry,m_nNumNewCountry+1);
+ if (gslc_ElemXListboxInsertItemAt(&m_gui,m_pElemListbox,0,acTxt)) {
+ // successfully added new country
+ m_nNumNewCountry++;
+ gslc_ElemSetTxtStr(&m_gui, m_pElemSel, searchCountryCode(acTxt));
+ } else {
+ gslc_ElemSetTxtStr(&m_gui, m_pElemSel, m_pEmptyStr);
+ gslc_PopupShow(&m_gui, E_PG_WARNING, true);
+ }
+ break;
+ case E_BTN_DEL:
+ nSelId = gslc_ElemXListboxGetSel(&m_gui, m_pElemListbox);
+ if (nSelId != XLISTBOX_SEL_NONE) {
+ gslc_ElemXListboxDeleteItemAt(&m_gui,m_pElemListbox,nSelId);
+ gslc_ElemSetTxtStr(&m_gui, m_pElemSel, m_pEmptyStr);
+ } else {
+ Serial.println("No country selected for deletion");
+ }
+ break;
case E_BTN_OK:
- m_bQuit = true;
- gslc_ElemSetTxtStr(&m_gui,m_pElemOK,"DONE");
- gslc_ElemSetCol(&m_gui,m_pElemOK,GSLC_COL_RED,GSLC_COL_BLACK,GSLC_COL_BLACK);
+ gslc_PopupHide(&m_gui);
break;
//<Button Enums !End!>
default:
@@ -182,8 +251,10 @@ bool CbListbox(void* pvGui, void* pvElemRef, int16_t nSelId)
case E_LISTBOX:
// Update the status message with the selection
if (nSelId != XLISTBOX_SEL_NONE) {
- strncpy(acTxt, m_astrCountryCodes[nSelId], 5);
- gslc_ElemSetTxtStr(&m_gui, m_pElemSel, acTxt);
+ gslc_ElemXListboxGetItem(&m_gui,m_pElemListbox,nSelId,acTxt,sizeof(acTxt));
+ gslc_ElemSetTxtStr(&m_gui, m_pElemSel, searchCountryCode(acTxt));
+ } else {
+ gslc_ElemSetTxtStr(&m_gui, m_pElemSel, m_pEmptyStr);
}
break;
@@ -232,26 +303,27 @@ bool InitGUI()
//<InitGUI !Start!>
gslc_PageAdd(&m_gui,E_PG_MAIN,m_asPage1Elem,MAX_ELEM_PG_MAIN_RAM,m_asPage1ElemRef,MAX_ELEM_PG_MAIN);
+ gslc_PageAdd(&m_gui,E_PG_WARNING,m_asPopup1Elem,MAX_ELEM_PG_WARNING_RAM,m_asPopup1ElemRef,MAX_ELEM_PG_WARNING);
// NOTE: The current page defaults to the first page added. Here we explicitly
// ensure that the main page is the correct page no matter the add order.
gslc_SetPageCur(&m_gui,E_PG_MAIN);
// Set Background to a flat color
- gslc_SetBkgndColor(&m_gui,GSLC_COL_GRAY_DK2);
+ gslc_SetBkgndColor(&m_gui,GSLC_COL_BLACK);
// -----------------------------------
// PAGE: E_PG_MAIN
// Create wrapping box for listbox E_LISTBOX and scrollbar
- pElemRef = gslc_ElemCreateBox(&m_gui,GSLC_ID_AUTO,E_PG_MAIN,(gslc_tsRect){17,75,200,100});
+ pElemRef = gslc_ElemCreateBox(&m_gui,GSLC_ID_AUTO,E_PG_MAIN,(gslc_tsRect){20,75,200,100});
gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_GRAY,GSLC_COL_GRAY_DK3,GSLC_COL_GRAY_DK2);
// Create listbox
pElemRef = gslc_ElemXListboxCreate(&m_gui,E_LISTBOX,E_PG_MAIN,&m_sListbox1,
- (gslc_tsRect){17+2,75+4,200-23,100-7},E_FONT_MONO9,
- (char*)&m_acListboxBuf1,sizeof(m_acListboxBuf1),0);
+ (gslc_tsRect){20+2,75+4,200-23,100-7},E_FREE_MONO9,
+ (uint8_t*)&m_acListboxBuf1,sizeof(m_acListboxBuf1),0);
gslc_ElemXListboxSetSize(&m_gui, pElemRef, 5, 1); // 5 rows, 1 columns
gslc_ElemXListboxItemsSetSize(&m_gui, pElemRef, XLISTBOX_SIZE_AUTO, XLISTBOX_SIZE_AUTO);
gslc_ElemSetTxtMarginXY(&m_gui, pElemRef, 5, 0);
@@ -275,37 +347,61 @@ bool InitGUI()
// Create vertical scrollbar for listbox
pElemRef = gslc_ElemXSliderCreate(&m_gui,E_LISTSCROLL1,E_PG_MAIN,&m_sListScroll1,
- (gslc_tsRect){17+200-21,75+4,20,100-8},0,12,0,5,true);
+ (gslc_tsRect){20+200-21,75+4,20,100-8},0,100,0,5,true);
gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_BLUE_LT1,GSLC_COL_BLACK,GSLC_COL_BLUE_LT1);
gslc_ElemXSliderSetPosFunc(&m_gui,pElemRef,&CbSlidePos);
m_pListSlider1 = pElemRef;
// Create E_TXT_COUNTRY_CODE runtime modifiable text
static char m_sDisplayText2[6] = "US";
- pElemRef = gslc_ElemCreateTxt(&m_gui,E_TXT_COUNTRY_CODE,E_PG_MAIN,(gslc_tsRect){125,45,105,23},
- (char*)m_sDisplayText2,6,E_FONT_SANS9);
+ pElemRef = gslc_ElemCreateTxt(&m_gui,E_TXT_COUNTRY_CODE,E_PG_MAIN,(gslc_tsRect){130,45,90,23},
+ (char*)m_sDisplayText2,6,E_FREE_SANS9);
gslc_ElemSetTxtAlign(&m_gui,pElemRef,GSLC_ALIGN_MID_MID);
gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_GRAY,GSLC_COL_GRAY_DK2,GSLC_COL_BLACK);
m_pElemSel = pElemRef;
// Create E_LBL_COUNTRYCD text label
- pElemRef = gslc_ElemCreateTxt(&m_gui,E_LBL_COUNTRYCD,E_PG_MAIN,(gslc_tsRect){14,45,121,23},
- (char*)"Country Code:",0,E_FONT_SANS9);
+ pElemRef = gslc_ElemCreateTxt(&m_gui,E_LBL_COUNTRYCD,E_PG_MAIN,(gslc_tsRect){10,45,121,23},
+ (char*)"Country Code:",0,E_FREE_SANS9);
gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_GRAY,GSLC_COL_GRAY_DK2,GSLC_COL_BLACK);
// Create E_LBL_TITLE text label
pElemRef = gslc_ElemCreateTxt(&m_gui,E_LBL_TITLE,E_PG_MAIN,(gslc_tsRect){49,20,141,23},
- (char*)"Country Chooser",0,E_FONT_SANS9);
+ (char*)"Country Chooser",0,E_FREE_SANS9);
gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_GRAY,GSLC_COL_GRAY_DK2,GSLC_COL_BLACK);
- // Create E_BTN_OK button with modifiable text label
- static char m_strbtn1[7] = "OK";
- pElemRef = gslc_ElemCreateBtnTxt(&m_gui,E_BTN_OK,E_PG_MAIN,
- (gslc_tsRect){157,190,60,30},
- (char*)m_strbtn1,7,E_FONT_SANS9,&CbBtnCommon);
- gslc_ElemSetTxtCol(&m_gui,pElemRef,GSLC_COL_WHITE);
+ // create E_BTN_ADD button with text label
+ pElemRef = gslc_ElemCreateBtnTxt(&m_gui,E_BTN_ADD,E_PG_MAIN,
+ (gslc_tsRect){140,190,80,30},(char*)"Insert New",0,E_BUILTIN_TXT5,&CbBtnCommon);
+ gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_GREEN_DK2,GSLC_COL_GREEN_DK4,GSLC_COL_GREEN_DK1);
+
+ // create E_BTN_DEL button with text label
+ pElemRef = gslc_ElemCreateBtnTxt(&m_gui,E_BTN_DEL,E_PG_MAIN,
+ (gslc_tsRect){20,190,80,30},(char*)"Delete",0,E_BUILTIN_TXT5,&CbBtnCommon);
gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_GREEN_DK2,GSLC_COL_GREEN_DK4,GSLC_COL_GREEN_DK1);
- m_pElemOK = pElemRef;
+
+ // -----------------------------------
+ // PAGE: E_PG_WARNING
+
+
+ // Create E_ELEM_BOX1 box
+ pElemRef = gslc_ElemCreateBox(&m_gui,E_ELEM_BOX1,E_PG_WARNING,(gslc_tsRect){50,50,250,150});
+ gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_GRAY,GSLC_COL_GRAY_LT3,GSLC_COL_GRAY_LT3);
+
+ // Create E_ELEM_TEXT4 text label
+ pElemRef = gslc_ElemCreateTxt(&m_gui,E_ELEM_TEXT4,E_PG_WARNING,(gslc_tsRect){60,70,100,25},
+ (char*)"WARNING:",0,E_BUILTIN_TXT10);
+ gslc_ElemSetTxtCol(&m_gui,pElemRef,GSLC_COL_RED);
+
+ // Create E_ELEM_TEXT5 text label
+ pElemRef = gslc_ElemCreateTxt(&m_gui,E_ELEM_TEXT5,E_PG_WARNING,(gslc_tsRect){60,120,228,10},
+ (char*)"Buffer too small to add more entries.",0,E_BUILTIN_TXT5);
+ gslc_ElemSetTxtCol(&m_gui,pElemRef,GSLC_COL_BLACK);
+ gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_GRAY,GSLC_COL_GRAY_LT3,GSLC_COL_GRAY_LT3);
+
+ // create E_BTN_OK button with text label
+ pElemRef = gslc_ElemCreateBtnTxt(&m_gui,E_BTN_OK,E_PG_WARNING,
+ (gslc_tsRect){250,150,40,40},(char*)"OK",0,E_BUILTIN_TXT5,&CbBtnCommon);
//<InitGUI !End!>
return true;
@@ -328,8 +424,10 @@ void setup()
// Load Fonts
// ------------------------------------------------
//<Load_Fonts !Start!>
- if (!gslc_FontSet(&m_gui,E_FONT_MONO9,GSLC_FONTREF_PTR,&FreeMono9pt7b,1)) { return; }
- if (!gslc_FontSet(&m_gui,E_FONT_SANS9,GSLC_FONTREF_PTR,&FreeSans9pt7b,1)) { return; }
+ if (!gslc_FontSet(&m_gui,E_BUILTIN_TXT10,GSLC_FONTREF_PTR,NULL,2)) { return; }
+ if (!gslc_FontSet(&m_gui,E_BUILTIN_TXT5,GSLC_FONTREF_PTR,NULL,1)) { return; }
+ if (!gslc_FontSet(&m_gui,E_FREE_MONO9,GSLC_FONTREF_PTR,&FreeMono9pt7b,1)) { return; }
+ if (!gslc_FontSet(&m_gui,E_FREE_SANS9,GSLC_FONTREF_PTR,&FreeSans9pt7b,1)) { return; }
//<Load_Fonts !End!>
// ------------------------------------------------

diff: Binary files a/examples/builder/ex31_bld_listbox/ex31_bld_listbox.prj and b/examples/builder/ex31_bld_listbox/ex31_bld_listbox.prj differ

diff:
@@ -70,28 +70,61 @@ extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
// - A Listbox control
// ============================================================================
-/*
+
// Basic debug functionality
+/*
void debug_ElemXListboxDump(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef)
{
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui, pElemRef);
gslc_tsXListbox* pListbox = (gslc_tsXListbox*)(pElem->pXData);
- char acTxt[40 + 1];
+ // Prevent runaway looping due to damaged buffer
+ // Don't ask why I know to do this - PaulC
+
+ int16_t nSafety=0;
+ char acTxt[50 + 1];
GSLC_DEBUG2_PRINT("Xlistbox:Dump (nBufPos=%d nItemCnt=%d)\n", pListbox->nBufItemsPos,pListbox->nItemCnt);
for (unsigned nInd = 0; nInd < pListbox->nBufItemsPos; nInd++) {
+ nSafety++;
+ if (nSafety > pListbox->nBufItemsMax) break;
char ch = pListbox->pBufItems[nInd];
if (ch == 0) {
- snprintf(acTxt, 40,"[%2u] = %02X = [NULL]", nInd, ch);
+ snprintf(acTxt, 40,"0x%04x: [%2u] = %02X = [NULL]", (char*)&pListbox->pBufItems[nInd],nInd, ch);
}
else {
- snprintf(acTxt, 40,"[%2u] = %02X = [%c]", nInd, ch, ch);
+ snprintf(acTxt, 40,"0x%04x: [%2u] = %02X = [%c]", (char*)&pListbox->pBufItems[nInd],nInd, ch, ch);
}
GSLC_DEBUG2_PRINT("XListbox:Dump: %s\n", acTxt);
}
}
*/
+char* gslc_ElemXListboxGetItemAddr(gslc_tsXListbox* pListbox, int16_t nItemCurSel)
+{
+ char* pBuf = NULL;
+ uint16_t nBufPos = 0;
+ uint16_t nItemInd = 0;
+ bool bFound = false;
+ while (1) {
+ if (nItemInd == nItemCurSel) {
+ bFound = true;
+ break;
+ }
+ if (nBufPos >= pListbox->nBufItemsMax) {
+ break;
+ }
+ if (pListbox->pBufItems[nBufPos] == 0) {
+ nItemInd++;
+ }
+ nBufPos++;
+ }
+ if (bFound) {
+ pBuf = (char*)&(pListbox->pBufItems[nBufPos]);
+ return pBuf;
+ } else {
+ return NULL;
+ }
+}
// Recalculate listbox item sizing if enabled
bool gslc_ElemXListboxRecalcSize(gslc_tsXListbox* pListbox,gslc_tsRect rElem)
@@ -262,7 +295,136 @@ bool gslc_ElemXListboxAddItem(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, const
return true;
}
-bool gslc_ElemXListboxGetItem(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nItemCurSel, char* pStrItem, uint8_t nStrItemLen)
+bool gslc_ElemXListboxInsertItemAt(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, uint16_t nInsertPos,
+ const char* pStrItem)
+{
+ gslc_tsXListbox* pListbox = (gslc_tsXListbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_LISTBOX, __LINE__);
+ if (!pListbox) return false;
+
+ int8_t nStrItemLen;
+ char* pBuf = NULL;
+ uint16_t nBufItemsPos = pListbox->nBufItemsPos;
+ uint16_t nBufItemsMax = pListbox->nBufItemsMax;
+
+ if (nInsertPos > pListbox->nItemCnt) {
+ GSLC_DEBUG2_PRINT("ERROR: ElemXListboxInsertItemAt() Current Count: %d Invalid Position %d\n",
+ pListbox->nItemCnt,nInsertPos);
+ return false;
+ }
+ nStrItemLen = strlen(pStrItem);
+
+ if (nStrItemLen == 0) {
+ // Nothing to add
+ return false;
+ }
+
+ // Ensure we won't overrun the buffer, including the terminator
+ if (nBufItemsPos + nStrItemLen + 1 > nBufItemsMax) {
+ GSLC_DEBUG2_PRINT("ERROR: ElemXListboxInsertItemAt() buffer too small\n", "");
+ return false;
+ }
+
+ // If the truncation left nothing to add, skip out now
+ if (nStrItemLen <= 0) {
+ return false;
+ }
+
+// GSLC_DEBUG2_PRINT("Xlistbox:InsertAt: %d\n", nInsertPos);
+// debug_ElemXListboxDump(pGui, pElemRef);
+
+ pBuf = gslc_ElemXListboxGetItemAddr(pListbox, nInsertPos);
+ // If position is incorrect, bail out...
+ if (pBuf == NULL) {
+ return false;
+ }
+
+ // Make a hole in the buffer to slot in the new item
+ char* pSrc = (char*)pListbox->pBufItems+nBufItemsPos-1;
+ char* pDest = pSrc+nStrItemLen+1;
+ int16_t nMoveLen = (int16_t)(pSrc - pBuf)+1;
+ uint8_t ch;
+ for (uint16_t nInd = 0; nInd < nMoveLen; nInd++) {
+ ch = *pSrc;
+ *pDest = ch;
+ pDest--;
+ pSrc--;
+ }
+
+ // Now slot in the new item
+ memcpy(pBuf, pStrItem, nStrItemLen+1);
+
+ // update our buffer information
+ pListbox->nBufItemsPos += nStrItemLen+1;
+ pListbox->nItemCnt++;
+
+// GSLC_DEBUG2_PRINT("Xlistbox:After InsertAt %d\n", nInsertPos);
+// debug_ElemXListboxDump(pGui, pElemRef);
+
+ // Indicate sizing may need update
+ pListbox->bNeedRecalc = true;
+
+ // Mark as needing full redraw
+ gslc_ElemSetRedraw(pGui, pElemRef, GSLC_REDRAW_FULL);
+
+ return true;
+}
+
+bool gslc_ElemXListboxDeleteItemAt(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, uint16_t nDeletePos)
+{
+ gslc_tsXListbox* pListbox = (gslc_tsXListbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_LISTBOX, __LINE__);
+ if (!pListbox) return false;
+
+ int8_t nStrItemLen;
+ char* pBuf = NULL;
+ uint16_t nBufItemsPos = pListbox->nBufItemsPos;
+ uint16_t nBufItemsMax = pListbox->nBufItemsMax;
+
+// GSLC_DEBUG2_PRINT("Xlistbox:DeleteAt: %d\n", nDeletePos);
+// debug_ElemXListboxDump(pGui, pElemRef);
+
+ pBuf = gslc_ElemXListboxGetItemAddr(pListbox, nDeletePos);
+ // If position is incorrect, bail out...
+ if (pBuf == NULL) {
+ return false;
+ }
+ nStrItemLen = strlen(pBuf);
+
+ // Pull items after this delete position up to delete this item
+ char* pSrc = (char*)pBuf+nStrItemLen+1;
+ char* pDest = (char*)pBuf;
+ char* pEndOfBuf = (char*)(pListbox->pBufItems+nBufItemsPos);
+ int16_t nMoveLen = (int16_t)(pEndOfBuf-pSrc)+1;
+ uint8_t ch;
+ if (nMoveLen > 1) {
+ for (uint16_t nInd = 0; nInd < nMoveLen; nInd++) {
+ ch = *pSrc;
+ *pDest = ch;
+ pDest++;
+ pSrc++;
+ }
+ }
+
+ // update our buffer information
+ pListbox->nBufItemsPos -= nStrItemLen+1;
+ pListbox->nItemCnt--;
+
+ // unselect item
+ gslc_ElemXListboxSetSel(pGui, pElemRef, XLISTBOX_SEL_NONE);
+
+// GSLC_DEBUG2_PRINT("Xlistbox:After DeleteAt %d\n", nDeletePos);
+// debug_ElemXListboxDump(pGui, pElemRef);
+
+ // Indicate sizing may need update
+ pListbox->bNeedRecalc = true;
+
+ // Mark as needing full redraw
+ gslc_ElemSetRedraw(pGui, pElemRef, GSLC_REDRAW_FULL);
+
+ return true;
+}
+
+bool gslc_ElemXListboxGetItem(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nItemCurSel, char* pStrItem,
+ uint8_t nStrItemLen)
{
gslc_tsXListbox* pListbox = (gslc_tsXListbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_LISTBOX, __LINE__);
if (!pListbox) return false;

diff:
@@ -190,6 +190,30 @@ void gslc_ElemXListboxReset(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef);
///
bool gslc_ElemXListboxAddItem(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, const char* pStrItem);
+///
+/// Insert an item in the listbox at a specific position
+///
+/// \param[in] pGui: Pointer to GUI
+/// \param[in] pElemRef: Ptr to Element Reference to update
+/// \param[in] nInsertPos: Insertion position
+/// \param[in] pStrItem: String to use when creating the listbox item
+///
+/// \return true if OK, false if fail (eg. insufficient buffer storage)
+///
+bool gslc_ElemXListboxInsertItemAt(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, uint16_t nInsertPos,
+ const char* pStrItem);
+
+///
+/// Insert an item in the listbox at a specific position
+///
+/// \param[in] pGui: Pointer to GUI
+/// \param[in] pElemRef: Ptr to Element Reference to update
+/// \param[in] nDeletePos: Position to delete
+///
+/// \return true if OK, false if fail
+///
+bool gslc_ElemXListboxDeleteItemAt(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, uint16_t nDeletePos);
+
///
/// Get the indexed listbox item
///
@@ -201,7 +225,8 @@ bool gslc_ElemXListboxAddItem(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, const
///
/// \return true if success, false if fail (eg. can't locate item)
///
-bool gslc_ElemXListboxGetItem(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nItemCurSel, char* pStrItem, uint8_t nStrItemLen);
+bool gslc_ElemXListboxGetItem(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nItemCurSel,
+ char* pStrItem, uint8_t nStrItemLen);
///


message: Toggle button rounded corners not rendering correctly issue 266

change_type: MODIFY

diff:
@@ -252,9 +252,6 @@ void gslc_ElemXTogglebtnToggleState(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef)
void gslc_ElemXTogglebtnDrawCircularHelp(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsXTogglebtn* pTogglebtn)
{
- // frame enabled?
- bool bFrameEn = pElem->nFeatures & GSLC_ELEM_FEA_FRAME_EN;
-
// Work out the sizes of the inner rectangles
gslc_tsRect rInner = gslc_ExpandRect(pElem->rElem,-1,-1);
@@ -267,22 +264,14 @@ void gslc_ElemXTogglebtnDrawCircularHelp(gslc_tsGui* pGui,gslc_tsElem* pElem,gsl
if (pTogglebtn->bOn) {
// draw our main body
- gslc_DrawFillRoundRect(pGui,rInner,rInner.h,pTogglebtn->colOnState);
+ gslc_DrawFillRoundRect(pGui,rInner,nRadius,pTogglebtn->colOnState);
// place thumb on left-hand side
gslc_DrawFillCircle(pGui,nLeftX,nLeftY,nRadius-1,pTogglebtn->colThumb);
- if (bFrameEn) {
- gslc_DrawFrameRoundRect(pGui,pElem->rElem,pElem->rElem.h,pElem->colElemFrame);
- gslc_DrawFrameCircle(pGui,nLeftX,nLeftY,nRadius,pElem->colElemFrame);
- }
} else {
// draw our main body
- gslc_DrawFillRoundRect(pGui,rInner,rInner.h,pTogglebtn->colOffState);
+ gslc_DrawFillRoundRect(pGui,rInner,nRadius,pTogglebtn->colOffState);
// place thumb on right-hand side
- gslc_DrawFillCircle(pGui,nRightX,nRightY,nRadius-1,pTogglebtn->colThumb);
- if (bFrameEn) {
- gslc_DrawFrameRoundRect(pGui,pElem->rElem,pElem->rElem.h,pElem->colElemFrame);
- gslc_DrawFrameCircle(pGui,nRightX,nRightY,nRadius,pElem->colElemFrame);
- }
+ gslc_DrawFillCircle(pGui,nRightX-1,nRightY,nRadius-1,pTogglebtn->colThumb);
}
}
@@ -338,6 +327,7 @@ bool gslc_ElemXTogglebtnDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedr
}
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
+// gslc_DrawFillRect(pGui,pElem->rElem,pElem->colElemFill);
if (pTogglebtn->bCircular) {
gslc_ElemXTogglebtnDrawCircularHelp(pGui, pElem, pTogglebtn);
@@ -375,7 +365,6 @@ bool gslc_ElemXTogglebtnTouch(void* pvGui,void* pvElemRef,gslc_teTouch eTouch,in
gslc_tsXTogglebtn* pTogglebtn = (gslc_tsXTogglebtn*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_TOGGLEBTN, __LINE__);
if (!pTogglebtn) return false;
- //gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
bool bStateOld = pTogglebtn->bOn;
switch(eTouch) {

license: MIT License

repo: impulseadventure/guislice


message: fix to XTogglebtn not showing frame issue 275

diff:
@@ -255,6 +255,9 @@ void gslc_ElemXTogglebtnDrawCircularHelp(gslc_tsGui* pGui,gslc_tsElem* pElem,gsl
// Work out the sizes of the inner rectangles
gslc_tsRect rInner = gslc_ExpandRect(pElem->rElem,-1,-1);
+ // frame enabled?
+ bool bFrameEn = pElem->nFeatures & GSLC_ELEM_FEA_FRAME_EN;
+
// work out our circle positions
uint16_t nRadius = rInner.h / 2;
int16_t nLeftX = rInner.x + nRadius;
@@ -267,11 +270,23 @@ void gslc_ElemXTogglebtnDrawCircularHelp(gslc_tsGui* pGui,gslc_tsElem* pElem,gsl
gslc_DrawFillRoundRect(pGui,rInner,nRadius,pTogglebtn->colOnState);
// place thumb on right-hand side
gslc_DrawFillCircle(pGui,nRightX-1,nRightY,nRadius-1,pTogglebtn->colThumb);
+ if (bFrameEn) {
+// ON HX8357 and ILI9341 with TFT_eSPI if we do rounded rect frame we get
+// something that looks like two reversed parenthesis )button( around button
+ gslc_DrawFrameCircle(pGui,nRightX,nRightY,nRadius-1,pElem->colElemFrame);
+// gslc_DrawFrameRoundRect(pGui,pElem->rElem,pElem->rElem.h,pElem->colElemFrame);
+ gslc_DrawFrameRoundRect(pGui,rInner,nRadius,pElem->colElemFrame);
+ }
} else {
// draw our main body
gslc_DrawFillRoundRect(pGui,rInner,nRadius,pTogglebtn->colOffState);
// place thumb on left-hand side
gslc_DrawFillCircle(pGui,nLeftX,nLeftY,nRadius-1,pTogglebtn->colThumb);
+ if (bFrameEn) {
+ gslc_DrawFrameCircle(pGui,nLeftX,nLeftY,nRadius-1,pElem->colElemFrame);
+// gslc_DrawFrameRoundRect(pGui,,pElem->rElem.h,pElem->colElemFrame);
+ gslc_DrawFrameRoundRect(pGui,rInner,nRadius,pElem->colElemFrame);
+ }
}
}


message: Issue 459 MCU restarts using spinner control

diff:
//
// =======================================================================
/// \file XSpinner.c
-
-
+///
+/// Author: Paul Conti
+/// Date: 2022-04-06
+/// Modified to use Virtual Elements instead of Compound
+///
// GUIslice library
#include "GUIslice.h"
@@ -66,11 +69,10 @@ extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
// ----------------------------------------------------------------------------
-#if (GSLC_FEATURE_COMPOUND)
// ============================================================================
// Extended Element: Spinner
-// - Spinner element demonstrates a simple up/down counter
-// - This is a compound element containing two buttons and
+// - Spinner element - a simple up/down counter
+// - This is a element containing two virtual buttons and
// a text area to represent the current value
// ============================================================================
@@ -94,20 +96,15 @@ gslc_tsElemRef* gslc_ElemXSpinnerCreate(gslc_tsGui* pGui, int16_t nElemId, int16
// determine size of our text box
// first calculate number of digits required
- int16_t nTxtBoxW,nTxtBoxH,nBtnPosY;
char acTxtNum[XSPINNER_STR_LEN];
- // FIXME: Consider replacing the sprintf() with an optimized function to
- // conserve RAM. Potentially leverage GSLC_DEBUG2_PRINT().
- nTxtBoxW = rElem.w - 2 * (nButtonSz);
+ int16_t nTxtBoxW = rElem.w - 2 * (nButtonSz);
// Determine the maximum width of a digit, we will use button size for height.
// now we can work out our rectangle
- nTxtBoxH = rElem.h;
-
- nBtnPosY = rElem.y + (rElem.h - nButtonSz) / 2;
+ int16_t nTxtBoxH = rElem.h;
- // set our intial value for our text field
- snprintf(acTxtNum, XSPINNER_STR_LEN - 1, "%d", nVal);
+ int16_t nBtnPosY = rElem.y + (rElem.h - nButtonSz) / 2;
+ gslc_tsElemRef* pElemRef = NULL;
gslc_tsElem sElem;
// Initialize composite element
@@ -115,7 +112,8 @@ gslc_tsElemRef* gslc_ElemXSpinnerCreate(gslc_tsGui* pGui, int16_t nElemId, int16
sElem.nFeatures |= GSLC_ELEM_FEA_FRAME_EN;
sElem.nFeatures |= GSLC_ELEM_FEA_FILL_EN;
sElem.nFeatures |= GSLC_ELEM_FEA_CLICK_EN;
- sElem.nFeatures &= ~GSLC_ELEM_FEA_GLOW_EN; // Don't need to glow outer element
+ sElem.nFeatures |= GSLC_ELEM_FEA_GLOW_EN;
+ sElem.nFeatures |= GSLC_ELEM_FEA_FOCUS_EN;
sElem.nGroup = GSLC_GROUP_ID_NONE;
pXData->nCounter = nVal;
@@ -123,15 +121,10 @@ gslc_tsElemRef* gslc_ElemXSpinnerCreate(gslc_tsGui* pGui, int16_t nElemId, int16
pXData->nMax = nMax;
pXData->nIncr = nIncr;
pXData->pfuncXInput = cbInput;
-
-
- // Initialize the collection of sub-elements within the compound element
- // - XSELNUM_COMP_CNT defines the maximum number of sub-elements we have allocated space for
- // - Note that this example shows RAM being used for storage
- gslc_CollectReset(&pXData->sCollect, pXData->asElem, XSPINNER_COMP_CNT, pXData->asElemRef, XSPINNER_COMP_CNT);
-
+ pXData->nFontId = nFontId;
sElem.pXData = (void*)(pXData);
+
// Specify the custom drawing callback
sElem.pfuncXDraw = &gslc_ElemXSpinnerDraw;
// Specify the custom touch tracking callback
@@ -142,91 +135,44 @@ gslc_tsElemRef* gslc_ElemXSpinnerCreate(gslc_tsGui* pGui, int16_t nElemId, int16
sElem.colElemFrame = GSLC_COL_GRAY;
sElem.colElemFrameGlow = GSLC_COL_WHITE;
+ // create our bounding rectangles for each virtual element
- // Now create the sub elements
- // - Ensure page is set to GSLC_PAGE_NONE so that
- // we create the element struct but not add it to a specific page.
- // - When we create an element with GSLC_PAGE_NONE it is
- // saved in the GUI's temporary element storage.
- // - When we have finished creating / styling the element, we then
- // copy it into the permanent sub-element storage
-
- // - The element IDs assigned to the sub-elements are
- // arbitrary (with local scope in the compound element),
- // so they don't need to be unique globally across the GUI.
- gslc_tsElemRef* pElemRefTmp = NULL;
- gslc_tsElem* pElemTmp = NULL;
- gslc_tsElemRef* pElemRef = NULL;
-
- // Determine offset coordinate of compound element so that we can
- // specify relative positioning during the sub-element Create() operations.
- int16_t nOffsetX = rElem.x;
- int16_t nOffsetY = rElem.y;
-
- gslc_tsRect rSubElem;
-
- // Create button sub-element
+ // increment button
+ pXData->rSubElemBtnInc.x = rElem.x+nTxtBoxW;
+ pXData->rSubElemBtnInc.y = nBtnPosY;
+ pXData->rSubElemBtnInc.w = nButtonSz;
+ pXData->rSubElemBtnInc.h = nButtonSz;
+ pXData->rSubElemBtnInc = gslc_ExpandRect(pXData->rSubElemBtnInc, -1, -1);
strcpy(pXData->acIncr,"\030");
- rSubElem = (gslc_tsRect) { nOffsetX+nTxtBoxW, nBtnPosY, nButtonSz, nButtonSz };
- rSubElem = gslc_ExpandRect(rSubElem, -1, -1);
- pElemRefTmp = gslc_ElemCreateBtnTxt(pGui, SPINNER_ID_BTN_INC, GSLC_PAGE_NONE,
- rSubElem, pXData->acIncr, 2, nFontId, &gslc_ElemXSpinnerClick);
- gslc_ElemSetCol(pGui, pElemRefTmp, (gslc_tsColor) { 0, 0, 192 }, (gslc_tsColor) { 0, 0, 128 }, (gslc_tsColor) { 0, 0, 224 });
- gslc_ElemSetTxtCol(pGui, pElemRefTmp, GSLC_COL_WHITE);
- pElemTmp = gslc_GetElemFromRef(pGui, pElemRefTmp);
- gslc_CollectElemAdd(pGui, &pXData->sCollect, pElemTmp, GSLC_ELEMREF_DEFAULT);
-
- // Create button sub-element
+
+ // decrement button
+ pXData->rSubElemBtnDec.x = rElem.x+nTxtBoxW+nButtonSz;
+ pXData->rSubElemBtnDec.y = nBtnPosY;
+ pXData->rSubElemBtnDec.w = nButtonSz;
+ pXData->rSubElemBtnDec.h = nButtonSz;
+ pXData->rSubElemBtnDec = gslc_ExpandRect(pXData->rSubElemBtnDec, -1, -1);
strcpy(pXData->acDecr,"\031");
- rSubElem = (gslc_tsRect) { nOffsetX+nTxtBoxW+nButtonSz, nBtnPosY, nButtonSz, nButtonSz };
- rSubElem = gslc_ExpandRect(rSubElem, -1, -1);
- pElemRefTmp = gslc_ElemCreateBtnTxt(pGui, SPINNER_ID_BTN_DEC, GSLC_PAGE_NONE,
- rSubElem, pXData->acDecr, 2, nFontId, &gslc_ElemXSpinnerClick);
- gslc_ElemSetCol(pGui, pElemRefTmp, (gslc_tsColor) { 0, 0, 192 }, (gslc_tsColor) { 0, 0, 128 }, (gslc_tsColor) { 0, 0, 224 });
- gslc_ElemSetTxtCol(pGui, pElemRefTmp, GSLC_COL_WHITE);
- pElemTmp = gslc_GetElemFromRef(pGui, pElemRefTmp);
- gslc_CollectElemAdd(pGui, &pXData->sCollect, pElemTmp, GSLC_ELEMREF_DEFAULT);
- // Create dynamic text sub-element
- // - Note that we are using string storage in the extended element data
- // structure (pXData).
- rSubElem = (gslc_tsRect) { nOffsetX, nOffsetY, nTxtBoxW, nTxtBoxH };
- rSubElem = gslc_ExpandRect(rSubElem, -1, -1);
- gslc_StrCopy(pXData->acElemTxt[0], acTxtNum, XSPINNER_STR_LEN);
- pElemRefTmp = gslc_ElemCreateTxt(pGui, SPINNER_ID_TXT, GSLC_PAGE_NONE,
- rSubElem, pXData->acElemTxt[0], XSPINNER_STR_LEN, nFontId);
- gslc_ElemSetTxtAlign(pGui, pElemRefTmp, GSLC_ALIGN_MID_MID);
- pElemTmp = gslc_GetElemFromRef(pGui, pElemRefTmp);
- gslc_CollectElemAdd(pGui, &pXData->sCollect, pElemTmp, GSLC_ELEMREF_DEFAULT);
-
-
- // Now proceed to add the compound element to the page
+ // text field
+ pXData->rSubElemTxt.x = rElem.x;
+ pXData->rSubElemTxt.y = nBtnPosY;
+ pXData->rSubElemTxt.w = nTxtBoxW;
+ pXData->rSubElemTxt.h = nTxtBoxH;
+ pXData->rSubElemTxt = gslc_ExpandRect(pXData->rSubElemTxt, -1, -1);
+ // set our intial value for our text field
+ // TODO: Consider replacing the sprintf() with an optimized function to
+ // conserve RAM. Potentially leverage gslc_DebugPrintf().
+ snprintf(pXData->acElemTxt[0], XSPINNER_STR_LEN - 1, "%d", nVal);
+
+ // Now proceed to add the element to the page
if (nPage != GSLC_PAGE_NONE) {
pElemRef = gslc_ElemAdd(pGui,nPage,&sElem,GSLC_ELEMREF_DEFAULT);
-
// save our ElemRef for the callback
pXData->pElemRef = pElemRef;
-
- // Now propagate the parent relationship to enable a cascade
- // of redrawing from low-level elements to the top
- gslc_CollectSetParent(pGui, &pXData->sCollect, pElemRef);
-
return pElemRef;
}
- else {
- GSLC_DEBUG2_PRINT("ERROR: ElemXSpinnerCreate(%s) Compound elements inside compound elements not supported\n", "");
return NULL;
- // TODO: For now, disable compound elements within
- // compound elements. If we want to enable this, we
- // would probably use the temporary element reference
- // the GUI.
- // Save as temporary element for further processing
- //pGui->sElemTmp = sElem; // Need fixing
- //return &(pGui->sElemTmp); // Need fixing
-
- }
-
}
bool gslc_ElemXSpinnerSetChars(void* pvGui,gslc_tsElemRef* pElemRef,uint8_t cIncr, uint8_t cDecr)
@@ -237,16 +183,124 @@ bool gslc_ElemXSpinnerSetChars(void* pvGui,gslc_tsElemRef* pElemRef,uint8_t cInc
gslc_tsXSpinner* pSpinner = (gslc_tsXSpinner*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_SPINNER, __LINE__);
if (!pSpinner) return false;
- char acIncr[2] = { cIncr, '\0'};
- char acDecr[2] = { cDecr, '\0'};
- gslc_tsElemRef* pElemRefUp = gslc_CollectFindElemById(pGui,&pSpinner->sCollect,SPINNER_ID_BTN_INC);
- gslc_ElemSetTxtStr(pGui,pElemRefUp,acIncr);
- gslc_tsElemRef* pElemRefDown = gslc_CollectFindElemById(pGui,&pSpinner->sCollect,SPINNER_ID_BTN_DEC);
- gslc_ElemSetTxtStr(pGui,pElemRefDown,acDecr);
+ pSpinner->acIncr[0] = cIncr;
+ pSpinner->acIncr[1] = '\0';
+ pSpinner->acDecr[0] = cDecr;
+ pSpinner->acDecr[1] = '\0';
return true;
}
+void gslc_XSpinnerDrawVirtualTxt(gslc_tsGui* pGui,gslc_tsRect rElem,int16_t nFontId,char* pValStr,int8_t eTxtAlign,
+ gslc_tsColor cColFrame, gslc_tsColor cColFill, gslc_tsColor cColTxt)
+{
+ gslc_tsElem sElem;
+ gslc_tsElem* pVirtualElem = &sElem;
+
+ gslc_ResetElem(pVirtualElem);
+ pVirtualElem->colElemFill = cColFill;
+ pVirtualElem->colElemFillGlow = cColFill;
+ pVirtualElem->colElemFrame = cColFrame;
+ pVirtualElem->colElemFrameGlow = cColFrame;
+ pVirtualElem->colElemText = cColTxt;
+ pVirtualElem->colElemTextGlow = cColTxt;
+
+ pVirtualElem->nFeatures = GSLC_ELEM_FEA_NONE;
+ pVirtualElem->nFeatures |= GSLC_ELEM_FEA_FRAME_EN;
+ pVirtualElem->nFeatures |= GSLC_ELEM_FEA_FILL_EN;
+ pVirtualElem->nFeatures |= GSLC_ELEM_FEA_VALID;
+
+ pVirtualElem->rElem = rElem;
+ pVirtualElem->pTxtFont = gslc_FontGet(pGui,nFontId);
+
+ pVirtualElem->eTxtFlags = GSLC_TXT_DEFAULT;
+ pVirtualElem->eTxtFlags = (pVirtualElem->eTxtFlags & ~GSLC_TXT_ALLOC) | GSLC_TXT_ALLOC_EXT;
+ pVirtualElem->eTxtAlign = eTxtAlign;
+ pVirtualElem->nTxtMarginX = 2;
+ pVirtualElem->nTxtMarginY = 2;
+
+ // Render the virtual element
+ gslc_tsElemRef sElemRef;
+ sElemRef.pElem = pVirtualElem;
+ sElemRef.eElemFlags = GSLC_ELEMREF_SRC_RAM | GSLC_ELEMREF_VISIBLE;
+
+ // In GSLC_LOCAL_STR mode, pStrBuf is a local character
+ // array, so we need to perform a deep string copy here.
+ // When not in GSLC_LOCAL_STR mode, pStrBuf is just a
+ // pointer, so we can simply update the pointer.
+ #if (GSLC_LOCAL_STR)
+ // Deep copy
+ gslc_StrCopy(pVirtualElem->pStrBuf,pValStr,GSLC_LOCAL_STR_LEN);
+ #else
+ // Shallow copy
+ pVirtualElem->nStrBufMax = 0; // Read-only string buffer
+ pVirtualElem->pStrBuf = pValStr;
+ #endif
+ gslc_ElemDrawByRef(pGui,&sElemRef,GSLC_REDRAW_FULL);
+
+}
+
+void gslc_XSpinnerDrawVirtualBtn(gslc_tsGui* pGui, gslc_tsRect rElem,
+ char* pStrBuf,uint8_t nStrBufMax,int16_t nFontId, gslc_tsColor cColFrame,
+ gslc_tsColor cColFill, gslc_tsColor cColFillGlow, gslc_tsColor cColText,
+ bool bRoundedEn, bool bGlow, bool bFocus)
+{
+ gslc_tsElem sElem;
+ gslc_tsElem* pVirtualElem = &sElem;
+
+ gslc_ResetElem(pVirtualElem);
+ pVirtualElem->colElemFill = cColFill;
+ pVirtualElem->colElemFillGlow = cColFillGlow;
+ pVirtualElem->colElemFrame = cColFrame;
+ pVirtualElem->colElemFrameGlow = cColFrame;
+ pVirtualElem->colElemText = cColText;
+ pVirtualElem->colElemTextGlow = cColText;
+ pVirtualElem->nFeatures = GSLC_ELEM_FEA_NONE;
+ pVirtualElem->nFeatures |= GSLC_ELEM_FEA_FRAME_EN;
+ pVirtualElem->nFeatures |= GSLC_ELEM_FEA_FILL_EN;
+ pVirtualElem->nFeatures |= GSLC_ELEM_FEA_VALID;
+ pVirtualElem->nFeatures |= GSLC_ELEM_FEA_GLOW_EN;
+ pVirtualElem->nFeatures |= GSLC_ELEM_FEA_FOCUS_EN;
+
+ pVirtualElem->nType = GSLC_TYPE_BTN;
+
+ pVirtualElem->rElem = rElem;
+ pVirtualElem->pTxtFont = gslc_FontGet(pGui,nFontId);
+
+ pVirtualElem->nStrBufMax = nStrBufMax;
+ #if (GSLC_LOCAL_STR)
+ // Deep copy
+ gslc_StrCopy(pVirtualElem->pStrBuf,pStrBuf,GSLC_LOCAL_STR_LEN);
+ #else
+ // Shallow copy
+ pVirtualElem->pStrBuf = pStrBuf;
+ #endif
+
+ pVirtualElem->eTxtFlags = GSLC_TXT_DEFAULT;
+ pVirtualElem->eTxtFlags = (pVirtualElem->eTxtFlags & ~GSLC_TXT_ALLOC) | GSLC_TXT_ALLOC_EXT;
+ pVirtualElem->eTxtAlign = GSLC_ALIGN_MID_MID;
+ pVirtualElem->nTxtMarginX = 0;
+ pVirtualElem->nTxtMarginY = 0;
+
+ // For the text buttons, optionally use rounded profile if enabled
+ if (bRoundedEn) {
+ pVirtualElem->nFeatures |= GSLC_ELEM_FEA_ROUND_EN;
+ } else {
+ pVirtualElem->nFeatures &= ~GSLC_ELEM_FEA_ROUND_EN;
+ }
+
+ // Render the virtual element
+ gslc_tsElemRef sElemRef;
+ sElemRef.pElem = pVirtualElem;
+ sElemRef.eElemFlags = GSLC_ELEMREF_SRC_RAM | GSLC_ELEMREF_VISIBLE;
+
+ // Update any other element reference states
+ gslc_ElemSetGlow(pGui,&sElemRef,bGlow);
+ gslc_ElemSetFocus(pGui,&sElemRef,bFocus);
+
+ gslc_ElemDrawByRef(pGui,&sElemRef,GSLC_REDRAW_FULL);
+
+}
// Redraw the compound element
// - When drawing a compound element, we clear the background
@@ -257,36 +311,38 @@ bool gslc_ElemXSpinnerDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
gslc_tsXSpinner* pSpinner = (gslc_tsXSpinner*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_SPINNER, __LINE__);
- if (!pSpinner) return false;
+ if (pSpinner == NULL) {
+ return false;
+ }
bool bGlow = (pElem->nFeatures & GSLC_ELEM_FEA_GLOW_EN) && gslc_ElemGetGlow(pGui,pElemRef);
- // Draw the compound element fill (background)
+ // Draw the element fill (background)
// - Should only need to do this in full redraw
if (eRedraw == GSLC_REDRAW_FULL) {
gslc_DrawFillRect(pGui,pElem->rElem,(bGlow)?pElem->colElemFillGlow:pElem->colElemFill);
}
- // Draw the sub-elements
- // - For now, force redraw of entire compound element
- gslc_tsCollect* pCollect = &pSpinner->sCollect;
- if (eRedraw != GSLC_REDRAW_NONE) {
- uint8_t sEventSubType = GSLC_EVTSUB_DRAW_NEEDED;
+ // Optionally, draw a frame around the element
if (eRedraw == GSLC_REDRAW_FULL) {
- sEventSubType = GSLC_EVTSUB_DRAW_FORCE;
- }
- gslc_tsEvent sEvent = gslc_EventCreate(pGui, GSLC_EVT_DRAW, sEventSubType, (void*)(pCollect), NULL);
- gslc_CollectEvent(pGui, sEvent);
+ gslc_DrawFrameRect(pGui, pElem->rElem, (bGlow) ? pElem->colElemFrameGlow : pElem->colElemFrame);
}
- // Optionally, draw a frame around the compound element
- // - This could instead be done by creating a sub-element
- // of type box.
- // - We don't need to show any glowing of the compound element
+ // draw our virtual elements
- if (eRedraw == GSLC_REDRAW_FULL) {
- gslc_DrawFrameRect(pGui, pElem->rElem, (bGlow) ? pElem->colElemFrameGlow : pElem->colElemFrame);
- }
+ // Create dynamic button sub-element
+ gslc_XSpinnerDrawVirtualBtn(pGui, pSpinner->rSubElemBtnInc, pSpinner->acIncr, 2, pSpinner->nFontId,
+ GSLC_COL_BLUE_DK2, GSLC_COL_BLUE_DK4, GSLC_COL_BLUE_DK1, GSLC_COL_WHITE,
+ false, false, false);
+
+ // Create dynamic button sub-element
+ gslc_XSpinnerDrawVirtualBtn(pGui, pSpinner->rSubElemBtnDec, pSpinner->acDecr, 2, pSpinner->nFontId,
+ GSLC_COL_BLUE_DK2, GSLC_COL_BLUE_DK4, GSLC_COL_BLUE_DK1, GSLC_COL_WHITE,
+ false, false, false);
+
+ // Create dynamic text sub-element
+ gslc_XSpinnerDrawVirtualTxt(pGui, pSpinner->rSubElemTxt, pSpinner->nFontId, pSpinner->acElemTxt[0],
+ GSLC_ALIGN_MID_MID, GSLC_COL_BLUE_DK2, GSLC_COL_BLACK, GSLC_COL_WHITE);
// Clear the redraw flag
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_NONE);
@@ -318,29 +374,41 @@ void gslc_ElemXSpinnerSetCounter(gslc_tsGui* pGui,gslc_tsXSpinner* pSpinner,int1
}
pSpinner->nCounter = nCount;
- // Determine new counter text
- // FIXME: Consider replacing the printf() with an optimized function to
- // conserve RAM. Potentially leverage GSLC_DEBUG2_PRINT().
- char acStrNew[GSLC_LOCAL_STR_LEN];
- snprintf(acStrNew,GSLC_LOCAL_STR_LEN,"%hd",pSpinner->nCounter);
+ // Update counter text
+ // TODO: Consider replacing the printf() with an optimized function to
+ // conserve RAM. Potentially leverage gslc_DebugPrintf().
+ snprintf(pSpinner->acElemTxt[0],GSLC_LOCAL_STR_LEN,"%hd",pSpinner->nCounter);
+
+}
+
+// Map touch event a it bounding rectangle position that matches one
+// of the virtual sub-elements of this control. Once its found
+// return the sub-element ID (defined at the top of this sourcefile) to the caller.
+// returns -1 if no buttons touched (text field).
+int16_t gslc_XSpinnerMapEvent(gslc_tsGui* pGui, gslc_tsXSpinner* pConfig, int16_t nRelX, int16_t nRelY)
+{
- // Update the element
- gslc_tsElemRef* pElemRef = gslc_CollectFindElemById(pGui,&pSpinner->sCollect,SPINNER_ID_TXT);
- gslc_ElemSetTxtStr(pGui,pElemRef,acStrNew);
+ //GSLC_DEBUG_PRINT("[gslc_XSpinnerMapEvent] nRelX=%d nRelY=%d\n",nRelX,nRelY);
+ // Scan for buttons
+ if (gslc_IsInRect(nRelX,nRelY,pConfig->rSubElemBtnInc)) {
+ //GSLC_DEBUG_PRINT("match: ID=SPINNER_ID_BTN_INC\n", "");
+ return SPINNER_ID_BTN_INC;
+ }
+ if (gslc_IsInRect(nRelX,nRelY,pConfig->rSubElemBtnDec)) {
+ //GSLC_DEBUG_PRINT("match: ID=SPINNER_ID_BTN_DEC\n", "");
+ return SPINNER_ID_BTN_DEC;
}
+ // text field touched
+ return -1;
+}
-// Handle the compound element main functionality
// - This routine is called by gslc_ElemEvent() to handle
// any click events that resulted from the touch tracking process.
-// - The code here will generally represent the core
-// functionality of the compound element and any communication
-// between sub-elements.
-// - pvElemRef is a void pointer to the element ref being tracked. From
-// the pElemRefParent member we can get the parent/compound element
-// data structures.
-bool gslc_ElemXSpinnerClick(void* pvGui,void *pvElemRef,gslc_teTouch eTouch,int16_t nX,int16_t nY)
+// - pvElemRef is a void pointer to the element ref being tracked
+// containing multiple virtual elements.
+bool gslc_ElemXSpinnerTouch(void* pvGui,void *pvElemRef,gslc_teTouch eTouch,int16_t nRelX,int16_t nRelY)
{
#if defined(DRV_TOUCH_NONE)
return false;
@@ -348,36 +416,47 @@ bool gslc_ElemXSpinnerClick(void* pvGui,void *pvElemRef,gslc_teTouch eTouch,int1
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
- gslc_tsElem* pElem = gslc_GetElemFromRefD(pGui, pElemRef, __LINE__);
- if (!pElem) return false;
-
- // Fetch the parent of the clicked element which is the compound
- // element itself. This enables us to access the extra control data.
- gslc_tsElemRef* pElemRefParent = pElem->pElemRefParent;
- if (pElemRefParent == NULL) {
- GSLC_DEBUG2_PRINT("ERROR: ElemXSpinnerClick(%s) parent ElemRef ptr NULL\n","");
- return false;
- }
+ gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
+ gslc_tsRect rElem = pElem->rElem;
- gslc_tsElem* pElemParent = gslc_GetElemFromRef(pGui,pElemRefParent);
- gslc_tsXSpinner* pSpinner = (gslc_tsXSpinner*)(pElemParent->pXData);
+ gslc_tsXSpinner* pSpinner = (gslc_tsXSpinner*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_SPINNER, __LINE__);
if (pSpinner == NULL) {
- GSLC_DEBUG2_PRINT("ERROR: ElemXSpinnerClick() element (ID=%d) has NULL pXData\n",pElem->nId);
+ GSLC_DEBUG2_PRINT("ERROR: gslc_ElemXSpinnerTouch() element (ID=%d) has NULL pXData\n",pElem->nId);
return false;
}
- // Begin the core compound element functionality
+ // setup variables
+ bool bGlowingOld = gslc_ElemGetGlow(pGui,pElemRef);
+ bool bFocusedOld = gslc_ElemGetFocus(pGui,pElemRef);
+ int16_t nSubElemId = 0;
+ int16_t nAbsX = nRelX + rElem.x;
+ int16_t nAbsY = nRelY + rElem.y;
+ bool bChanged = false;
int nCounter = pSpinner->nCounter;
- // Handle the various button presses
+ // Begin the core touch functionality
+ // by Handling the various button presses
GSLC_CB_INPUT pfuncXInput = NULL;
- if (eTouch == GSLC_TOUCH_UP_IN) {
-
- // Get the tracked element ID
- gslc_tsElemRef* pElemRefTracked = pSpinner->sCollect.pElemRefTracked;
- gslc_tsElem* pElemTracked = gslc_GetElemFromRef(pGui,pElemRefTracked);
- int nSubElemId = pElemTracked->nId;
-
+ switch(eTouch) {
+
+ case GSLC_TOUCH_DOWN_IN:
+ // Start glowing as must be over it
+ gslc_ElemSetGlow(pGui,pElemRef,true);
+ break;
+
+ case GSLC_TOUCH_MOVE_IN:
+ gslc_ElemSetGlow(pGui,pElemRef,true);
+ break;
+
+ case GSLC_TOUCH_MOVE_OUT:
+ gslc_ElemSetGlow(pGui,pElemRef,false);
+ break;
+
+ case GSLC_TOUCH_UP_IN:
+ // End glow
+ gslc_ElemSetGlow(pGui,pElemRef,false);
+ // Determine which virtual field matches the touch
+ nSubElemId = gslc_XSpinnerMapEvent(pGui, pSpinner, nAbsX, nAbsY);
if (nSubElemId == SPINNER_ID_BTN_INC) {
// Increment button
if (nCounter < pSpinner->nMax) {
@@ -394,36 +473,33 @@ bool gslc_ElemXSpinnerClick(void* pvGui,void *pvElemRef,gslc_teTouch eTouch,int1
}
+ bChanged = true;
// Invoke the callback function
pfuncXInput = pSpinner->pfuncXInput;
if (pfuncXInput != NULL) {
(*pfuncXInput)(pvGui, (void*)(pSpinner->pElemRef), XSPINNER_CB_STATE_UPDATE, NULL);
}
+ break;
+ case GSLC_TOUCH_UP_OUT:
+ // End glow
+ gslc_ElemSetGlow(pGui,pElemRef,false);
+ break;
- } // eTouch
-
- return true;
-#endif // !DRV_TOUCH_NONE
-}
-
-bool gslc_ElemXSpinnerTouch(void* pvGui,void* pvElemRef,gslc_teTouch eTouch,int16_t nRelX,int16_t nRelY)
-{
-#if defined(DRV_TOUCH_NONE)
+ default:
return false;
-#else
- gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
- gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
- gslc_tsXSpinner* pSpinner = (gslc_tsXSpinner*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_SPINNER, __LINE__);
- if (!pSpinner) return false;
-
- // Get Collection
- gslc_tsCollect* pCollect = &pSpinner->sCollect;
+ }
- return gslc_CollectTouchCompound(pvGui, pvElemRef, eTouch, nRelX, nRelY, pCollect);
+ // If the spinner changed state, redraw
+ if (bChanged ||
+ gslc_ElemGetGlow(pGui,pElemRef) != bGlowingOld ||
+// gslc_ElemGetEdit(pGui, pElemRef) != bEditingOld ||
+ gslc_ElemGetFocus(pGui,pElemRef) != bFocusedOld ){
+ gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
+ }
+ return true;
#endif // !DRV_TOUCH_NONE
}
-#endif // GSLC_FEATURE_COMPOUND
// ============================================================================

diff:
//
// =======================================================================
/// \file XSpinner.h
+///
+/// Author: Paul Conti
+/// Date: 2022-04-06
+/// Modified to use Virtual Elements instead of Compound
+///
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
-
-
-#if (GSLC_FEATURE_COMPOUND)
// ============================================================================
-// Extended Element: Spinner (Number Selector)
-// - Demonstration of a compound element consisting of
-// a counter text field along with an increment and
-// decrement button.
+// Extended Element: Spinner
+// - Spinner element - a simple up/down counter
+// - This is a element containing two virtual buttons and
+// a text area to represent the current value
// ============================================================================
// Define unique identifier for extended element type
@@ -76,11 +78,15 @@ typedef struct {
int16_t nCounter; ///< Current value
GSLC_CB_INPUT pfuncXInput; ///< Callback func ptr for input ready
gslc_tsElemRef* pElemRef; ///< Save our ElemRef for the callback
+ int16_t nFontId; ///< Configured font for Spinner
+
- // Internal sub-element members
- gslc_tsCollect sCollect; ///< Collection management for sub-elements
- gslc_tsElemRef asElemRef[XSPINNER_COMP_CNT]; ///< Storage for sub-element references
- gslc_tsElem asElem[XSPINNER_COMP_CNT]; ///< Storage for sub-elements
+ // store offset coordinate of virtual element so that we can
+ // specify relative positioning during the sub-element creation (drawing)
+ // and touch operations.
+ gslc_tsRect rSubElemTxt; ///< Our virtual Text Field
+ gslc_tsRect rSubElemBtnInc; ///< Our virtual Increment Text Button
+ gslc_tsRect rSubElemBtnDec; ///< Our virtual Decrement Text Button
// Provide storage for any dynamic text elements
// Simple example here uses fixed-length character array
@@ -193,8 +199,6 @@ bool gslc_ElemXSpinnerClick(void* pvGui,void *pvElemRef,gslc_teTouch eTouch,int1
///
bool gslc_ElemXSpinnerTouch(void* pvGui,void* pvElemRef,gslc_teTouch eTouch,int16_t nRelX,int16_t nRelY);
-#endif // GLSC_COMPOUND
-
// ============================================================================
// ------------------------------------------------------------------------


message: Break up long sentence and add missing newline

diff:
@@ -178,11 +178,13 @@ usr/share/oem
usr/share/oem/example.ign
```
-Add the `oem.cpio.gz` to your PXE boot directory and [append it][append-initrd] to the `initrd` line in your `pxelinux.cfg` and specify the path to the config:
+Add the `oem.cpio.gz` file to your PXE boot directory, then [append it][append-initrd] to the `initrd` line in your `pxelinux.cfg`. Finally, specify the URL of the config in the `kernel` line:
```
+...
initrd coreos_production_pxe_image.cpio.gz,oem.cpio.gz
kernel coreos_production_pxe.vmlinuz coreos.config.url=oem:///example.ign
+...
```
## Using CoreOS Container Linux

license: Apache License 2.0

repo: coreos/docs


message:
quay-enterprise/setup-elb.md: Heading fmt
Apply tiny fmt fix from
so that it doesn't go astray.

diff:
-#Running Quay Enterprise behind a Elastic Load Balancer
+#Running Quay Enterprise behind an Elastic Load Balancer
Running Quay Enterprise behind a load balancer is often desired for large installations. However, simply putting a load balancer in front of the Quay Enterprise has some unintended consequences:

original_message:
quay-enterprise/setup-elb.md: Heading fmt

Apply tiny fmt fix from https://github.com/coreos-inc/coreos-pages/pull/1234/
so that it doesn't go astray.


message: fleet/deprecated-features: Move doc from k8s dir

change_type: ADD

diff:
+# Deprecated functionality
+
+While fleet and Kubernetes are similar in functionality, some fleet features do not have direct equivalents in Kubernetes. Workarounds exist for many of these cases. Several of these features and workarounds are outlined below.
+
+## Container Dependencies
+
+Fleet uses systemd service dependencies to outline a limited dependency graph. When units are co-located, then containers may be specified to start in a specific order; only beginning a service after others it depends on have begun. This is not really a fleet feature but rather a systemd feature. It is limited by the design and features of systemd.
+
+There are two workarounds for this in Kubernetes:
+
+1. Grouping related containers in a Pod.
+2. [Init containers][k8s-init-containers]
+
+### Grouping containers in Pods
+
+This is the most straightforward to approach the problem. Pods specs can contain multiple containers. By grouping related containers in one Pod, Kubernetes will co-locate them and monitor if all of the containers are running.
+
+[comment]: # (TODO: Include an example?)
+
+### Init containers
+
+[Init containers][k8s-init-containers] are containers that run before a Pod starts up. They can be used to manage assets, wait for services, and perform general setup. A pod is not scheduled until it's init containers complete.
+
+[comment]: # (TODO: Include an example?)
+
+## Graceful Exit Command (ExecStop)
+
+Fleet uses the systemd option [ExecStop][fleet-execstop] to instruct systemd how to stop a service gracefully. (The fleet ExecStop feature exhibits a [bug depending on how service termination is invoked][fleet-exec-issue].)
+
+While this exact feature does not exist in Kubernetes, the `ExecPreStop` does have an analogue: `lifecycle.preStop`.
+
+A Pod [lifecycle.preStop][lifecycle-hooks] directive specifies a command run before Kubernetes terminates an application with `SIGTERM`. This provides a mechanism to perform pre-termination actions to stop applications gracefully.
+
+Here is an example of using `lifecycle.preStop`, inspired by the Kubernetes docs:
+
+```yaml
+apiVersion: v1
+kind: Pod
+metadata:
+ name: web-server
+spec:
+ containers:
+ - name: nginx
+ image: nginx
+ ports:
+ - containerPort: 80
+ lifecycle:
+ preStop:
+ exec:
+ # SIGTERM triggers a quick exit; gracefully terminate instead
+ command: ["/usr/sbin/nginx","-s","quit"]
+```
+
+[comment]: # (TODO: Think of a better example for preStop. Need a clearer demo.)
+
+After a grace period, a running application in the pod will be killed via `SIGTERM`. The pod's `terminationGracePeriodSeconds` defaults to 30 seconds, but can be set to a longer period.
+
+More information can be found in the [Kubernetes Pods user guide][prestop].
+
+[fleet-exec-issue]: https://github.com/coreos/fleet/issues/1000
+[fleet-execstop]: https://coreos.com/fleet/docs/latest/launching-containers-fleet.html#run-a-container-in-the-cluster
+[k8s-init-containers]: http://kubernetes.io/docs/user-guide/pods/init-container/
+[lifecycle-hooks]: http://kubernetes.io/docs/user-guide/production-pods/#lifecycle-hooks-and-termination-notice
+[pod-deps-discussion]: https://github.com/kubernetes/kubernetes/issues/2385
+[prestop]: http://kubernetes.io/docs/user-guide/pods/#termination-of-pods


message:
kubernetes/daemon-sets-vs-global-unit: Polish
Spelling, grammar, styleguide nits

diff:
-# Kubernets Daemon Sets vs fleet Global units
+# Kubernetes DaemonSets vs fleet Global units
-Running a container on all nodes is a common task. Aggregating service logs, collecting node metrics, or running a networked storage cluster all require a container to be replicated across all nodes. In the world of fleet this is done with a [Global unit][global-units] and in the world of Kubernetes this is done with a [Daemon Set][daemon-sets].
+Running a container on all nodes is a common task. Aggregating service logs, collecting node metrics, or running a networked storage cluster all require a container to be replicated across all nodes. In fleet this is done with a [Global unit][global-units]. In Kubernetes, this is done with a [DaemonSet][daemon-sets].
## Global units
@@ -24,7 +24,7 @@ ExecStop=/usr/bin/docker stop busybox1
Global=true
```
-Can be run a verified with the following commands:
+Can be run and verified with the following commands:
```
$ fleetctl start hello.service
@@ -37,11 +37,11 @@ hello.service c46a8ace.../node2 active running
hello.service d77c07da.../node3 active running
```
-## Kubernetes DaemonSet
+## Kubernetes DaemonSets
-[Kubernetes DaemonSets][k8s-daemonset] offer a similar set of functionality to fleet global units in that they are a Kubernetes service which is run on all (or most) nodes in a cluster.
+[Kubernetes DaemonSets][k8s-daemonset] are a Kubernetes service which is run on all (or most) nodes in a cluster.
-DaemonSets can be executed in a few ways. The DaemonSet can monitor for a specific label, but not create any pods, **or** it can include a container definition in it's `spec` section.
+The DaemonSet can monitor for a specific label, but not create any pods, or it can include a container definition in its `spec` section.
### DaemonSet with Pod declaration
@@ -68,7 +68,7 @@ spec:
name: serverport
```
-When run the above would produce an output like so:
+When applied, the DaemonSet creates work on the cluster:
```
$ kubectl get nodes # Take a look at our nodes
@@ -78,7 +78,7 @@ worker1.infra.backend Ready 44m
worker2.infra.backend Ready 44m
$ kubectl create -f app-a.yaml # Deploy the DaemonSet
daemonset "app-a" created
-$ kubectl get pods -o wide # Inspect where they are running
+$ kubectl get pods -o wide # Inspect where DaemonSet pods are running
NAME READY STATUS RESTARTS AGE IP NODE
app-a-8bh7j 1/1 Running 0 2m 10.2.56.5 worker2.infra.backend
app-a-k8s6p 1/1 Running 0 2m 10.2.19.5 worker1.infra.backend
@@ -90,7 +90,7 @@ app-a 3 3 0 <none> 2m
# DaemonSets on a subset of hosts
-Sometimes a DaemonSet should only be run on a subset of nodes. This may be because of resource limitations, beta feature roll-out, restricted monitoring needs, who knows. By adding a `NodeSelector` to the `.spec.template.spec` we can achieve this limited-DaemonSet functionality.
+Sometimes a DaemonSet should only run on a subset of nodes. This may be because of resource limitations, beta feature roll-out, restricted monitoring needs, etc. Adding a `NodeSelector` to the `.spec.template.spec` restricts where the DaemonSet pods are scheduled.
```yaml
apiVersion: extensions/v1beta1
@@ -116,7 +116,7 @@ spec:
name: serverport
```
-If we run this **without** changing the labels on our nodes we will notice that the DaemonSet does not get run.
+When applying this DaemonSet before adding the chosen `app=app-b-node` label to any nodes, the DaemonSet does not get scheduled:
```
$ kubectl create -f app-b.yaml
@@ -126,7 +126,7 @@ NAME DESIRED CURRENT READY NODE-SELECTOR AGE
app-b 0 0 0 app=app-b-node 1m
```
-Once we add the label to one or more of our nodes the container starts to run on that pod.
+Once we add the label to one or more nodes, the pods are scheduled there:
```
$ kubectl label node worker1.infra.backend app=app-b-node
@@ -139,7 +139,7 @@ NAME DESIRED CURRENT READY NODE-SELECTOR AGE
app-b 1 1 0 app=app-b-node 2m
```
-And if we remove the label from our node the container stops running on that host:
+Removing the label from the node unschedules the pod running there:
```
$ kubectl label node worker1.infra.backend app-
@@ -149,7 +149,7 @@ NAME DESIRED CURRENT READY NODE-SELECTOR AGE
app-b 0 0 0 app=app-b-node 4m
```
-For more information read the [Kubernetes DaemonSets admin guide][k8s-daemonset] and the [DaemonSets design document][k8s-daemonset-design].
+For more information, check the [Kubernetes DaemonSets admin guide][k8s-daemonset] and the [DaemonSets design document][k8s-daemonset-design].
[daemon-sets]: http://kubernetes.io/docs/admin/daemons/
[global-units]: https://coreos.com/fleet/docs/latest/unit-files-and-scheduling.html#systemd-specifiers


message:
kubernetes/affinity: Polish
Spelling, grammar, styleguide nits
Change label for node selection to `example.com/load-balancer` with value `true` or `false`

diff:
@@ -8,7 +8,7 @@ In fleet dictating where a container gets run is called [Affinity and Anti-Affin
## Affinity in fleet
-In the world of fleet, affinity and anti-affinity are achieved through [fleet-specific options in systemd unit-files][fleet-affinity]. These options include:
+Affinity and anti-affinity are achieved through [fleet-specific options in systemd unit-files][fleet-affinity]. These options include:
* `MachineID`: Run a unit on a specific host.
* `MachineOf`: Run a unit on the same host as another unit.
@@ -17,7 +17,7 @@ In the world of fleet, affinity and anti-affinity are achieved through [fleet-sp
* `Global`: Runs a unit on every node.
* `Replaces`: Run a unit in place of another unit.
-These are described [in greater depth at the fleet documentation][fleet-specific-options].
+These are described [in detail in the fleet documentation][fleet-specific-options].
These options allow one to specify with arbitrary granularly how, where, and when to schedule a unit on a fleet cluster.
@@ -67,7 +67,7 @@ spec:
#### `nodeSelector` Example
-Let's say we're running a Kubernetes cluster on AWS and we want to run an Nginx pod on `m3.medium` instance. We also want a different `httpd` pod to only run in the `us-west-2` region and only on nodes with the `hello` key set to `world`. Here's how that `mypods.yaml` would look:
+Let's say we're running a Kubernetes cluster on AWS and we want to run an Nginx pod on `m3.medium` instance. We also want a different `httpd` pod to only run in the `us-west-2` region and only on nodes with the `example.com/load-balancer` key set to `true`. Here's how that `mypods.yaml` would look:
```yaml
apiVersion: v1
@@ -82,7 +82,7 @@ spec:
image: nginx
nodeSelector:
beta.kubernetes.io/instance-type: m3.medium
- hello: world
+ example.com/load-balancer: true
---
apiVersion: v1
kind: Pod
@@ -115,7 +115,7 @@ httpd 1/1 Running 0 1m
nginx 0/1 Pending 0 1m
```
-This is because our worker nodes don't meet one of the `nginx` pod requirements; neither have the `hello` key set to `world`!
+This is because our worker nodes don't meet one of the `nginx` pod requirements; neither have the `example.com/load-balancer` key set to `true`:
```
$ kubectl get nodes --show-labels
@@ -125,8 +125,8 @@ ip-10-0-0-188.us-west-2.compute.internal Ready 47m
ip-10-0-0-50.us-west-2.compute.internal Ready,SchedulingDisabled 47m beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=m3.medium,beta.kubernetes.io/os=linux,failure-domain.beta.kubernetes.io/region=us-west-2,failure-domain.beta.kubernetes.io/zone=us-west-2c,kubernetes.io/hostname=ip-10-0-0-50.us-west-2.compute.internal
```
-If we add the `hello=world` key to one of our nodes, the `nginx` pod will get scheduled to that node.
-Once we have the `hello` key set to `world`, the `nginx` pod will have a node to be assigned to and it will automatically start running.
+If we add the `example.com/load-balancer=true` key to one of our nodes, the `nginx` pod will get scheduled to that node.
+Once we have the `example.com/load-balancer` key set to `true`, the `nginx` pod will be scheduled.
```
$ kubectl get pods
@@ -135,7 +135,7 @@ httpd 1/1 Running 0 1m
nginx 0/1 Pending 0 1m
$ kubectl label node \
ip-10-0-0-187.us-west-2.compute.internal \
- hello=world
+ example.com/load-balancer=true
node "ip-10-0-0-187.us-west-2.compute.internal" labeled
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
@@ -143,26 +143,26 @@ httpd 1/1 Running 0 9m 10.2.26.5 ip-10-0-0-187.us-
nginx 1/1 Running 0 9m 10.2.26.6 ip-10-0-0-187.us-west-2.compute.internal
```
-Keep in mind: **when a node label changes, pods are not moved**. We can demonstrate this by changing the `hello` key on `ip-10-0-0-187.us-west-2.compute.internal` to `not-world`, and then add the `hello:world` lable to our other worker node to see what happens:
+**When a node label changes, pods are not moved**. We can demonstrate this by changing the `example.com/load-balancer` key on `ip-10-0-0-187.us-west-2.compute.internal` to `false`, then adding the `example.com/load-balancer=true` label to our other worker node to see what happens:
```
-$ kubectl label nodes --overwrite ip-10-0-0-187.us-west-2.compute.internal hello=not-world
+$ kubectl label nodes --overwrite ip-10-0-0-187.us-west-2.compute.internal example.com/load-balancer=false
node "ip-10-0-0-187.us-west-2.compute.internal" labeled
-$ kubectl label nodes ip-10-0-0-188.us-west-2.compute.internal hello=world
+$ kubectl label nodes ip-10-0-0-188.us-west-2.compute.internal example.com/load-balancer=true
node "ip-10-0-0-188.us-west-2.compute.internal" labeled
$ kubectl get nodes --show-labels
NAME STATUS AGE LABELS
-ip-10-0-0-187.us-west-2.compute.internal Ready 1h [...],hello=not-world,[...]
-ip-10-0-0-188.us-west-2.compute.internal Ready 1h [...],hello=world,[...]
+ip-10-0-0-187.us-west-2.compute.internal Ready 1h [...],example.com/load-balancer=false,[...]
+ip-10-0-0-188.us-west-2.compute.internal Ready 1h [...],example.com/load-balancer=true,[...]
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
httpd 1/1 Running 0 15m 10.2.26.5 ip-10-0-0-187.us-west-2.compute.internal
nginx 1/1 Running 0 15m 10.2.26.6 ip-10-0-0-187.us-west-2.compute.internal
```
-As you can see, the both pods keep running on the same host, even though the `httpd` pod should have moved. Further httpd pods will be assigned to the second node.
+As you can see, both pods keep running on the same host, because the initial `httpd` pod isn't moved or unscheduled. Later httpd pods will be assigned to the second node, according to the new `example.com/load-balancer=true` label.
-### `affinity`
+### Affinity
Kubernetes also has a more nuanced way of setting affinity called [`nodeAffinity` and `podAffinity`][k8s-node-affinity]. These are fields in under `Pod` metadata and take automatic or user-defined metadata to dictate where to schedule pods. `affinity` differs from `nodeSelector` in the following ways:
@@ -265,7 +265,6 @@ spec:
image: httpd
```
-`nodeAffinity` and `podAffinity` will *eventually* replace `nodeSelector`. For now `nodeAffinty` does everything `nodeSelector` does **and more**.
[k8s-node-affinity]: http://kubernetes.io/docs/user-guide/node-selection/#alpha-features-affinity-and-anti-affinity
[k8s-node-selector]: http://kubernetes.io/docs/user-guide/node-selection/


message:
service-dependencies: polish/style
Minor edits

diff:
# Service startup dependencies
-Service startup often demands an order of operations for functional dependencies. For instance your application depends on a caching system, without the caching container the entire service will fall on it's face. The simplest solution to this problem is to create a service dependency in which one container only starts after another has successfully begun running.
-
+Services often depend on other services, and must start in a certain order. For example, an application that depends on a caching system should start after the cache. fleet and Kubernetes express such dependencies in different ways, but achive the same effect of controlling the order in which applications are executed.
## fleet: ExecStartPre
Fleet uses the systemd `ExecStartPre` `[Service]` directive [to ensure a command is run before a service starts][fleet-exec-pre], and the `Requires` `[Unit]` directive to ensure a dependency unit is running before a unit starts.
-For instance one might create a file `myapp.service` which looks like this:
+For instance, one might create a unit file `myapp.service`:
```
[Unit]
@@ -24,8 +23,7 @@ ExecStart=/usr/bin/docker run --name busybox1 busybox /bin/sh -c "trap 'exit 0'
ExecStop=/usr/bin/docker stop busybox1
```
-This depends on `docker.sevice` and before beggining the application does some cleanup work with the three `ExecStartPre` commands which kill, remove, and pull the application's container.
-
+This unit depends on `docker.sevice`, and before starting, the application does some housekeeping work with the three `ExecStartPre` commands which kill, remove, and pull the application's container.
## Kubernetes: init containers
@@ -35,11 +33,11 @@ This depends on `docker.sevice` and before beggining the application does some c
* Run to completion before the next init container.
* All run to completion before the specified Pod.
-The feature is currently a beta feature of Kubernetes and so can only be invoked with raw JSON in the `.metadata.annotations` section of a Kubernetes specification file.
+The feature is currently a beta feature of Kubernetes v1.5.x, and must be specified in the `.metadata.annotations` of a Kubernetes manifest file.
### Example: init container fetching data
-An example of using an init container to download some local data for use in a container later looks like this:
+This example uses an init container to download some data for use in a container. The init container fetches the Kubernetes home page so that the nginx container can serve it:
```yaml
apiVersion: v1
@@ -77,7 +75,8 @@ spec:
### Example: Delaying pod startup
-One way we can solve the first example (waiting for a a caching service before starting our the application) is by creating an init container which runs and monitors for the caching Pod. Once the application's caching Pod is up and running the monitoring container exits and the main service begins running.
+
+One way to wait for a caching service before starting a primary application is by creating an init container to ping the caching Pod. Once the caching Pod is up and running, the cache checking container exits and the main Pod starts.
Application `yaml` file:
@@ -120,9 +119,9 @@ spec:
name: redis-pod-port
```
-The above application container specifies an init container which continuously pings the `redis-service`; once it successfully reaches that service the init-container exists and the pod which depends on redis continues to be spun up.
+The above application container specifies an init container which continuously pings the `redis-service`. Once it successfully reaches that service, the init-container exists and the pod that depends on redis can continue.
-You can test this by creating the writing the above into a file `app.yaml` and monitoring the startup process of the pod.
+You can test this by writing the above into a file `app.yaml` and monitoring the startup process of the pod.
```
$ kubectl create -f app.yaml
@@ -163,7 +162,7 @@ spec:
containerPort: 6379
```
-We can complete the exercise by copying the above into a file `redis.yaml` and begin create that service and pod.
+We can complete the exercise by copying the above into a file `redis.yaml` and create that service and pod:
```
$ kubectl create -f redis.yaml
@@ -179,8 +178,8 @@ app-pod 1/1 Running 0 8m
redis-pod 1/1 Running 0 2m
```
-As we can see once the `redis-service` was created the `app-pod` successfully completed the initialization and the pod was created.
+Once the `redis-service` was created, the `app-pod` successfully completed initialization and the pod was created.
+
[fleet-exec-pre]: https://coreos.com/fleet/docs/latest/launching-containers-fleet.html#run-a-container-in-the-cluster
-[k8s-init-containers]: http://kubernetes.io/docs/user-guide/production-pods/#handling-initialization
-[k8s-nit-containers-design]: https://github.com/kubernetes/community/blob/master/contributors/design-proposals/container-init.md
+[k8s-init-containers]: https://kubernetes.io/docs/concepts/abstractions/init-containers/


message: fleet/service-dependencies: Typo fixes

diff:
@@ -37,7 +37,7 @@ The feature is currently a beta feature of Kubernetes v1.5.x, and must be specif
### Example: init container fetching data
-This example uses an init container to download some data for use in a container. The init container fetches the Kubernetes home page so that the nginx container can serve it:
+This example uses an init container to download some data. The init container fetches the Kubernetes home page so that the nginx container can serve it:
```yaml
apiVersion: v1
@@ -119,9 +119,9 @@ spec:
name: redis-pod-port
```
-The above application container specifies an init container which continuously pings the `redis-service`. Once it successfully reaches that service, the init-container exists and the pod that depends on redis can continue.
+This manifest specifies an init container which continuously pings the `redis-service`. Once it successfully reaches that service, the init-container exits and the pod that depends on redis can continue.
-You can test this by writing the above into a file `app.yaml` and monitoring the startup process of the pod.
+You can test this by writing the above into a file `app.yaml` and monitoring the startup process of the pod:
```
$ kubectl create -f app.yaml
@@ -162,7 +162,7 @@ spec:
containerPort: 6379
```
-We can complete the exercise by copying the above into a file `redis.yaml` and create that service and pod:
+We can complete the exercise by copying the above into a file `redis.yaml` to create the pod and service:
```
$ kubectl create -f redis.yaml
@@ -178,7 +178,7 @@ app-pod 1/1 Running 0 8m
redis-pod 1/1 Running 0 2m
```
-Once the `redis-service` was created, the `app-pod` successfully completed initialization and the pod was created.
+Once the `redis-service` was created, the `app-pod` successfully completed initialization.
[fleet-exec-pre]: https://coreos.com/fleet/docs/latest/launching-containers-fleet.html#run-a-container-in-the-cluster

original_message: fleet/service-dependencies: Typo fixes


message: fleet/service-dependencies: Trim intro

diff:
# Service startup dependencies
-Services often depend on other services, and must start in a certain order. For example, an application that depends on a caching system should start after the cache. fleet and Kubernetes express such dependencies in different ways, but achive the same effect of controlling the order in which applications are executed.
+Services often depend on other services, and must start in a certain order. For example, an application that depends on a caching system should start after the cache. fleet and Kubernetes express such dependencies in different ways.
## fleet: ExecStartPre

original_message: fleet/service-dependencies: Trim intro


message: qe: add doc on required postgres package for 2.1.0

diff:
+# Installing Contributor Extensions for Postgres
+
+As of release 2.1.0 Quay Enterprise requires the [pg_trgm](https://www.postgresql.org/docs/current/static/pgtrgm.html) extension when using Postgres. This extension ships as part of the [Additional Supplied Modules](https://www.postgresql.org/docs/current/static/contrib.html). The requirements to allow extensions to be installed can be satisfied via package management tools on Debian and RedHat-based systems.
+
+## Debian/Ubuntu
+
+```
+# apt-get update
+# apt-get install postgresql-contrib -y
+```
+
+## Redhat/CentOS
+
+```
+# yum install postgresql-contrib
+```
+## Fedora
+
+```
+# dnf install postgresql-contrib
+```
+
+## Docker
+The [library/postgres](https://hub.docker.com/_/postgres/) container includes `postgresql-contrib` package by default.
+
+If using a container based on an OS above simply modify the Dockerfile to install `postgresql-contrib` package. If using an OS base that is not listed in may be required install `contrib` from [source](https://www.postgresql.org/docs/current/static/contrib.html).


message:
Documentation/getting-started: Polish
a little phrasing
add link to upgrade from v2 doc

diff:
@@ -10,7 +10,7 @@ Application containers running on your cluster can read and write data into etcd
Container Linux's `etcd-member.service` systemd unit knows how to fetch and run the current etcd v3.x container image, providing etcd v3 without requiring the binary to be present in every default OS installation.
-To enable the etcd v3 service, first ensure that `etcd2.service` is disabled.
+To enable the etcd v3 service, first ensure that `etcd2.service` is disabled. To upgrade an existing etcd v2 cluster rather than deploy a new one, start with the [etcd v2 to v3 upgrade doc][etcd-v3-upgrade].
```
$ systemctl disable etcd2.service
@@ -26,7 +26,7 @@ $ systemctl start etcd-member.service
$ systemctl status etcd-member.service
```
-This can be automated at first boot using [Ignition][ignition-docs]. The following is an example of the Ignition config you might use for this task:
+etcd v3 startup can be configured at a new node's first boot with [Ignition][ignition-docs] provisioning. The following Ignition config enables the `etcd-member` etcd v3 service:
```json
{
@@ -243,4 +243,6 @@ $ curl http://127.0.0.1:2379/v2/keys/foo
Full etcd API Docs
Projects using etcd
-[ignition-docs]: https://coreos.com/ignition/docs/latest/getting-started.html
+
+[etcd-v3-upgrade]: https://github.com/coreos/etcd/blob/master/Documentation/upgrades/upgrade_3_0.md
+[ignition-docs]: https://github.com/coreos/ignition/blob/master/doc/getting-started.md

original_message:
Documentation/getting-started: Polish

- a little phrasing
- add link to upgrade from v2 doc


message:
Update and rename installing-contributor-extensions-postgres.md to postgres-additional-modules.md
adds reference style links
grammar fixes
add section about RDS

change_type: DELETE

diff:
-# Installing Contributor Extensions for Postgres
-
-As of release 2.1.0 Quay Enterprise requires the [pg_trgm](https://www.postgresql.org/docs/current/static/pgtrgm.html) extension when using Postgres. This extension ships as part of the [Additional Supplied Modules](https://www.postgresql.org/docs/current/static/contrib.html). The requirements to allow extensions to be installed can be satisfied via package management tools on Debian and RedHat-based systems.
-
-## Debian/Ubuntu
-
-```
-# apt-get update
-# apt-get install postgresql-contrib -y
-```
-
-## Redhat/CentOS
-
-```
-# yum install postgresql-contrib
-```
-## Fedora
-
-```
-# dnf install postgresql-contrib
-```
-
-## Docker
-The [library/postgres](https://hub.docker.com/_/postgres/) container includes `postgresql-contrib` package by default.
-
-If using a container based on an OS above simply modify the Dockerfile to install `postgresql-contrib` package. If using an OS base that is not listed in may be required install `contrib` from [source](https://www.postgresql.org/docs/current/static/contrib.html).

diff:
+# Installing Contributor Extensions for Postgres
+
+As of release 2.1.0, Quay Enterprise requires the [pg_trgm][pg_trm] extension when using PostgreSQL. This extension is part of the [Additional Supplied Modules][Additional Supplied Modules]. These modules can be installed with standard package management tools on Debian and RedHat-based systems.
+
+## Debian/Ubuntu
+
+```
+# apt-get update
+# apt-get install postgresql-contrib
+```
+
+## Redhat/CentOS
+
+```
+# yum install postgresql-contrib
+```
+## Fedora
+
+```
+# dnf install postgresql-contrib
+```
+
+## Docker
+The [library/postgres][library/postgres] container includes the `postgresql-contrib` package.
+
+If using a container based on one of the above operating systems, modify the container's Dockerfile to install the postgresql-contrib package. Containers built FROM other operating systems may need to [install the additional modules from source][source].
+
+## PostgreSQL on Amazon RDS
+
+The `postgresql-contrib package` is included.
+
+[pg_trm]: https://www.postgresql.org/docs/current/static/pgtrgm.html
+[Additional Supplied Modules]: https://www.postgresql.org/docs/current/static/contrib.html
+[library/postgres]: https://hub.docker.com/_/postgres/
+[source]: https://www.postgresql.org/docs/current/static/contrib.html


message: postgres-addn-modules: Standardize ref link labels

diff:
# Installing Contributor Extensions for Postgres
-As of release 2.1.0, Quay Enterprise requires the [pg_trgm][pg_trm] extension when using PostgreSQL. This extension is part of the [Additional Supplied Modules][Additional Supplied Modules]. These modules can be installed with standard package management tools on Debian and RedHat-based systems.
+As of release 2.1.0, Quay Enterprise requires the [pg_trgm][postgres-trgm] extension when using PostgreSQL. This extension is part of the [Additional Supplied Modules][postgres-additional-modules]. These modules can be installed with standard package management tools on Debian and RedHat-based systems.
## Debian/Ubuntu
@@ -21,15 +21,16 @@ As of release 2.1.0, Quay Enterprise requires the [pg_trgm][pg_trm] extension wh
```
## Docker
-The [library/postgres][library/postgres] container includes the `postgresql-contrib` package.
+The [library/postgres][postgres-contrib-docker] container includes the `postgresql-contrib` package.
-If using a container based on one of the above operating systems, modify the container's Dockerfile to install the postgresql-contrib package. Containers built FROM other operating systems may need to [install the additional modules from source][source].
+If using a container based on one of the above operating systems, modify the container's Dockerfile to install the postgresql-contrib package. Containers built FROM other operating systems may need to [install the additional modules from source][source-install].
## PostgreSQL on Amazon RDS
The `postgresql-contrib package` is included.
-[pg_trm]: https://www.postgresql.org/docs/current/static/pgtrgm.html
-[Additional Supplied Modules]: https://www.postgresql.org/docs/current/static/contrib.html
-[library/postgres]: https://hub.docker.com/_/postgres/
-[source]: https://www.postgresql.org/docs/current/static/contrib.html
+
+[postgres-additional-modules]: https://www.postgresql.org/docs/current/static/contrib.html
+[postgres-contrib-docker]: https://hub.docker.com/_/postgres/
+[postgres-trgm]: https://www.postgresql.org/docs/current/static/pgtrgm.html
+[source-install]: https://www.postgresql.org/docs/current/static/contrib.html


message: q-e/: Update qe container version 2.1.0

diff:
@@ -28,7 +28,7 @@ One or more build workers will communicate with Quay Enterprise to build new con
Pull down the latest copy of the image. **Make sure to pull the version tagged matching your Quay Enterprise version**.
```sh
-docker pull quay.io/coreos/quay-builder:v2.0.1
+docker pull quay.io/coreos/quay-builder:v2.1.0
```
### Run the build worker image
@@ -45,7 +45,7 @@ Use the environment variable `SERVER` to tell the worker the hostname at which Q
Here's what the full command looks like:
```sh
-docker run --restart on-failure -e SERVER=wss://myquayenterprise -v /var/run/docker.sock:/var/run/docker.sock quay.io/coreos/quay-builder:v2.0.1
+docker run --restart on-failure -e SERVER=wss://myquayenterprise -v /var/run/docker.sock:/var/run/docker.sock quay.io/coreos/quay-builder:v2.1.0
```
When the container starts, each build worker will auto-register and start building containers once a job is triggered and it is assigned to a worker.

diff:
@@ -46,7 +46,7 @@ The `config.json` file will look like this:
}
```
-`config.json` contains your credentials for the `quay.io/coreos/quay` repository. Save this file to your Container Linux machine in `/home/core/.docker/config.json` and `/root/.docker/config.json`. You should now be able to execute `docker pull quay.io/coreos/quay:v2.0.3` to download the container.
+`config.json` contains your credentials for the `quay.io/coreos/quay` repository. Save this file to your Container Linux machine in `/home/core/.docker/config.json` and `/root/.docker/config.json`. You should now be able to execute `docker pull quay.io/coreos/quay:v2.1.0` to download the container.
## Setting up the directories
@@ -62,7 +62,7 @@ mkdir config
Run the following command, replacing `/local/path/to/the/config/directory` and `/local/path/to/the/storage/directory` with the absolute paths to the directories created above:
```
-sudo docker run --restart=always -p 443:443 -p 80:80 --privileged=true -v /local/path/to/the/config/directory:/conf/stack -v /local/path/to/the/storage/directory:/datastorage -d quay.io/coreos/quay:v2.0.3
+sudo docker run --restart=always -p 443:443 -p 80:80 --privileged=true -v /local/path/to/the/config/directory:/conf/stack -v /local/path/to/the/storage/directory:/datastorage -d quay.io/coreos/quay:v2.1.0
```
<img src="img/db-setup-full.png" class="img-center" alt="Quay Enterprise Setup Screen"/>

diff:
@@ -34,7 +34,7 @@ Obtain the quay container's `CONTAINER ID` with `docker ps`:
```
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
-5a3e82c4a75f quay.io/coreos/quay:v2.0.2 "/sbin/my_init" 24 hours ago Up 18 hours 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp, 8443/tcp grave_keller
+5a3e82c4a75f quay.io/coreos/quay:v2.1.0 "/sbin/my_init" 24 hours ago Up 18 hours 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp, 8443/tcp grave_keller
```
Restart the container with that ID:

diff:
@@ -22,7 +22,7 @@ spec:
secretName: quay-enterprise-config-secret
containers:
- name: quay-enterprise-app
- image: quay.io/coreos/quay:v2.0.1
+ image: quay.io/coreos/quay:v2.1.0
ports:
- containerPort: 80
volumeMounts:

original_message: q-e/: Update qe container version 2.1.0


message: build-support.md: Update quay-builder version, polish

diff:
@@ -50,10 +50,10 @@ docker run --restart on-failure -e SERVER=wss://myquayenterprise -v /var/run/doc
When the container starts, each build worker will auto-register and start building containers once a job is triggered and it is assigned to a worker.
-If Quay is setup to use SSL certificate that is not globally trusted, you must mount Quay's public SSL certificates into the quay-builder container's SSL trust store. Full command looks like:
+If Quay is setup to use a SSL certificate that is not globally trusted, for example a self-signed certificate, Quay's public SSL certificates must be mounted onto the `quay-builder` container's SSL trust store. An example command to mount a certificate directory found at the host's `/path/to/ssl` looks like:
```sh
-docker run --restart on-failure -e SERVER=wss://myquayenterprise -v /path/to/ssl:/usr/local/share/ca-certificates -v /var/run/docker.sock:/var/run/docker.sock quay.io/coreos/quay-builder:v2.0.1 /bin/sh -c "/usr/sbin/update-ca-certificates ; /quay-builder"
+docker run --restart on-failure -e SERVER=wss://myquayenterprise -v /path/to/ssl:/usr/local/share/ca-certificates -v /var/run/docker.sock:/var/run/docker.sock quay.io/coreos/quay-builder:v2.1.0 /bin/sh -c "/usr/sbin/update-ca-certificates ; /quay-builder"
```
### Setup GitHub build (optional)


message: STYLE: Tune description of code fence example

diff:
@@ -187,7 +187,7 @@ quay.io/coreosinc/coreos-pages-builder scripts/deploy stage
### Example: Documenting code blocks
-To format a code block in a document, insert triple backticks ` ``` ` ` ``` ` on a new line before and after the code block. A tag, such as `yaml`, `sh`, `json`, or `ini`, can be placed after the opening backticks to declare the language in the block.
+Insert triple backtick (grave accent) characters on a new line before and after a block of code. A tag, such as `yaml`, `sh`, `json`, or `ini`, can be placed after the opening backticks to declare the language in the block. Markdown syntax is not interpreted within the gated code block, but special characters are replaced with HTML entities.
```yaml
apiVersion: v1
@@ -204,6 +204,9 @@ spec:
app: etcd
```
+View this document's source to see the Markdown that generates the code block above.
+
+
## File name extension conventions
Some file types are commonly identified with more than one file name extension. For example, YAML is usually stored in files whose names end in either `.yml`, or `.yaml`. For the sake of consistency, use the file name extension designated in the following list when referring to or creating files of any of the listed types in CoreOS projects and their documentation.


message: STYLE: Heading hierarchy: Code blocks not part of CLI description styles

diff:
@@ -185,7 +185,7 @@ $ docker run --name docsbuilder \
quay.io/coreosinc/coreos-pages-builder scripts/deploy stage
```
-### Example: Documenting code blocks
+## Example: Documenting code blocks
Insert triple backtick (grave accent) characters on a new line before and after a block of code. A tag, such as `yaml`, `sh`, `json`, or `ini`, can be placed after the opening backticks to declare the language in the block. Markdown syntax is not interpreted within the gated code block, but special characters are replaced with HTML entities.
@@ -206,7 +206,6 @@ spec:
View this document's source to see the Markdown that generates the code block above.
-
## File name extension conventions
Some file types are commonly identified with more than one file name extension. For example, YAML is usually stored in files whose names end in either `.yml`, or `.yaml`. For the sake of consistency, use the file name extension designated in the following list when referring to or creating files of any of the listed types in CoreOS projects and their documentation.


message: integrations: Polish

diff:
# Integrations
-This document tracks projects that integrate with Container Linux. [Join the community](https://github.com/coreos/docs/), and help us keep the list up-to-date.
+This document tracks projects that integrate with Container Linux. [Join the community](https://github.com/coreos/docs/), and help us keep the list current.
## Projects
-[Deis Workflow](https://deis.com/workflow/): an open source PaaS for Kubernetes that runs atop Container Linux.
+[Deis Workflow](https://deis.com/workflow/): an open source PaaS for Kubernetes that runs on Container Linux.
[Amazon Web Services](https://aws.amazon.com/marketplace/pp/B01H62FDJM): Amazon's cloud computing solution. Offers Container Linux.
@@ -10,6 +10,6 @@ This document tracks projects that integrate with Container Linux. [Join the com
[Microsoft Azure](https://azuremarketplace.microsoft.com/en-us/marketplace/apps/category/compute?subcategories=operating-systems&page=1#): Microsoft's cloud computing solution. Offers Container Linux.
-[Digital Ocean](https://www.digitalocean.com/products/linux-distribution/coreos/): a cloud computing solution. Offers Container Linux.
+[Digital Ocean](https://www.digitalocean.com/products/linux-distribution/coreos/): An independent cloud computing solution. Offers Container Linux.
-[Packet.net](https://www.packet.net/promo/coreos/): a bare-metal hosted solution. Offers Container Linux.
\ No newline at end of file
+[Packet.net](https://www.packet.net/promo/coreos/): A hosted bare metal solution. Offers Container Linux.

original_message: integrations: Polish


message: production-users: Polish

diff:
# Production users
-This document tracks people and use cases for Container Linux in production. [Join the community](https://github.com/coreos/docs/), and help us keep the list up-to-date.
+This document tracks people and use cases for Container Linux in production. [Join the community](https://github.com/coreos/docs/) and help us keep the list current.
## [Ticketmaster](http://www.ticketmaster.com/)
+
Ticketmaster provides services for ticket management and entertainment venues. Tectonic, which [runs Container Linux](https://www.youtube.com/watch?v=wqXVKneP0Hg), is a key part of their infrastructure.
## [Packet.net](https://www.packet.net/)
-Packet.net is a bare-metal server provider. They [use Container Linux](https://www.quora.com/Who-uses-CoreOS-in-production) to power parts of their infrastructure.
+
+Packet.net is a hosted bare metal server provider. They [use Container Linux](https://www.quora.com/Who-uses-CoreOS-in-production) to power parts of their infrastructure.
## [Verizon Labs](http://www.verizon.com/about/careers/technology)
-Verizon Labs [uses Container Linux](https://www.youtube.com/watch?v=uwssG6eHYBQ&feature=youtu.be&list=PLlh6TqkU8kg_Eydfk1Nyt6iK7wM8v9bRA), because it's minimal and solves many many of the challenges inherent to running large clusters.
+
+Verizon Labs [uses Container Linux](https://www.youtube.com/watch?v=uwssG6eHYBQ&feature=youtu.be&list=PLlh6TqkU8kg_Eydfk1Nyt6iK7wM8v9bRA) because it's minimal and solves many many of the inherent challenges of running large clusters.
## [CA Technology](https://www.ca.com/us.html)
+
CA Technology [uses Container Linux](https://www.youtube.com/watch?v=1-SbSa_rwOg&feature=youtu.be&list=PLlh6TqkU8kg_Eydfk1Nyt6iK7wM8v9bRA) to run some of the Kubernetes solutions they provide to customers.

original_message: production-users: Polish


message: integrations: Blank link after headings

diff:
# Integrations
+
This document tracks projects that integrate with Container Linux. [Join the community](https://github.com/coreos/docs/), and help us keep the list current.
## Projects
+
[Deis Workflow](https://deis.com/workflow/): an open source PaaS for Kubernetes that runs on Container Linux.
[Amazon Web Services](https://aws.amazon.com/marketplace/pp/B01H62FDJM): Amazon's cloud computing solution. Offers Container Linux.

original_message: integrations: Blank link after headings


message: STYLE: Update GIFEE expansion. Add rules for project capitalization.

diff:
@@ -23,7 +23,24 @@ There are a few prescribed ways of writing frequently questioned words and phras
* The singular possessive form of CoreOS is *CoreOS's*. *CoreOS's mission is to secure the infrastructure that powers the Internet.*
* Deployments may occur *on-premises*, sometimes "on-prem," but never on-premise. A *premises* is a place. A *premise* is a proposition.
-* *GIFEE* is (currently) *Google's Infrastructure for Everyone Else*.
+* *GIFEE* was formerly *Google's Infrastructure for Everyone Else*, but now it is *Google's Infrastructure for EveryonE*.
+
+#### Project names are (mostly) proper nouns
+
+These project names are not capitalized, except when appearing as the first word of a sentence:
+
+* etcd
+* flannel
+* fleet
+* rkt
+
+The first word of a sentence is always capitalized.
+
+Other project names are proper nouns written with an initial capital letter. Examples include Ignition, Dex, and Matchbox.
+
+CoreOS is written in CamelCase. The Linux distribution is called CoreOS Container Linux.
+
+These capitalization rules are traditional and arcane. They should eventually give way to all project and product names being capitalized as proper nouns, except when given literally, e.g., `rkt run docker://nginx` or `/var/lib/rkt`.
## Source formatting


message: etcd/getting-started: Update button's link to etcd v3 client api doc

diff:
@@ -4,7 +4,7 @@ etcd is an open-source distributed key value store that provides shared configur
Application containers running on your cluster can read and write data into etcd. Common examples are storing database connection details, cache settings, feature flags, and more. This guide will walk you through a basic example of reading and writing to etcd then proceed to other features like TTLs, directories and watching a prefix. This guide is way more fun when you've got at least one Container Linux machine up and running — try it on [Amazon EC2](../os/booting-on-ec2.md) or locally with [Vagrant](../os/booting-on-vagrant.md).
-Complete etcd API Docs
+Complete etcd API Docs
## Setting up etcd


message: qe: update insert-custom-cert.md with k8s work around

diff:
@@ -50,3 +50,44 @@ $ docker exec -it 5a3e82c4a75f cat /etc/ssl/certs/storage.pem
-----BEGIN CERTIFICATE-----
MIIDTTCCAjWgAwIBAgIJAMVr9ngjJhzbMA0GCSqGSIb3DQEBCwUAMD0xCzAJBgNV
```
+
+
+## Add certs when deployed on Kubernetes
+
+When deployed on Kubernetes, QE mounts in a secret as a volume to store config assets. Unfortunately, this currently breaks the upload certificate function of the superuser panel.
+
+To get around this error, a base64 encoded certificate can be added to the secret *after* Quay Enterprise has been deployed.
+
+Begin by base64 encoing the contents of the certificate:
+
+```
+$ cat ca.crt
+-----BEGIN CERTIFICATE-----
+MIIDljCCAn6gAwIBAgIBATANBgkqhkiG9w0BAQsFADA5MRcwFQYDVQQKDA5MQUIu
+TElCQ09SRS5TTzEeMBwGA1UEAwwVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTE2
+MDExMjA2NTkxMFoXDTM2MDExMjA2NTkxMFowOTEXMBUGA1UECgwOTEFCLkxJQkNP
+UkUuU08xHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTCCASIwDQYJKoZI
+[...]
+-----END CERTIFICATE-----
+
+$ cat ca.crt | base64 -w 0
+[...]
+c1psWGpqeGlPQmNEWkJPMjJ5d0pDemVnR2QNCnRsbW9JdEF4YnFSdVd3PT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
+```
+
+Use the `kubectl` tool to edit the quay-enterprise-config-secret.
+```
+$ kubectl --namespace quay-enterprise edit secret/quay-enterprise-config-secret
+```
+
+Add an entry for the cert and paste the full base64 encoded string under the entry:
+
+```
+ custom-cert.crt:
+c1psWGpqeGlPQmNEWkJPMjJ5d0pDemVnR2QNCnRsbW9JdEF4YnFSdVd3PT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
+```
+
+Finally, recycle all QE pods for the certificate to be added to the QE container.
+
+
+


message: coreupdate: add section on syncing packages to on-premises-deployment.md

diff:
@@ -100,7 +100,7 @@ DBMAXACTIVE: 100
# (Optional) Enable if syncing with upstream CoreUpdate instances.
# Zero value is disabled.
# This should be disabled if you plan to synchronize packages manually.
-UPSTREAM_SYNC_INTERVAL: 0
+UPSTREAM_SYNC_INTERVAL: 1
# (Optional) enables TLS
#TLS_CERT_FILE:
@@ -196,6 +196,27 @@ To sync the "CoreOS" application it must exist and have the same application id
updateservicectl --server=http://localhost:8000 --user=admin --key=<previously-generated-key> app create --label=CoreOS --app-id=e96281a6-d1af-4bde-9a0a-97b76e56dc57
```
+This step needs to be repeated for the CoreOS ARM application:
+
+```bash
+updateservicectl --server=http://localhost:8000 --user=admin --key=<previously-generated-key> app create --label=CoreOS-ARM --app-id=103867da-e3a2-4c92-b0b3-7fbd7f7d8b71
+```
+
+#### Sync public upstream
+
+Create a `Public CoreOS` upstream:
+
+```bash
+updateservicectl upstream create --label="Public CoreOS" \
+--url="https://public.update.core-os.net"
+```
+
+Perform initial upstream sync:
+
+```bash
+updateservicectl upstream sync
+```
+
You can now point your browser to `http://localhost:8000` to view the control panel.
### Air-gapped package management


message: coreupdate: clarify unit of measure on-premises-deployment.md

diff:
@@ -98,9 +98,9 @@ DBMAXACTIVE: 100
#ENABLE_PACKAGE_UPLOADS: true
# (Optional) Enable if syncing with upstream CoreUpdate instances.
-# Zero value is disabled.
+# Value is minutes. Zero value is disabled.
# This should be disabled if you plan to synchronize packages manually.
-UPSTREAM_SYNC_INTERVAL: 1
+UPSTREAM_SYNC_INTERVAL: 10
# (Optional) enables TLS
#TLS_CERT_FILE: