Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Simple UIBorder widget that draws a border around the outside of its allocated space
  • Loading branch information
burksbuilds committed Oct 7, 2023
1 parent ec2d96a commit f462ede
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 0 deletions.
51 changes: 51 additions & 0 deletions examples/BordersAndBitmaps/BordersAndBitmaps.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include <U8g2lib.h>
#include <UiUiUi.h>

//XBM DATA
#define smiley_width 20
#define smiley_height 20
static const unsigned char smiley_bits[] U8X8_PROGMEM = {
0x80, 0x1f, 0x00, 0xe0, 0x7f, 0x00, 0x78, 0xe0, 0x01, 0x1c, 0x80, 0x03,
0x0c, 0x00, 0x03, 0x06, 0x00, 0x06, 0x06, 0x00, 0x06, 0xc3, 0x30, 0x0c,
0xc3, 0x30, 0x0c, 0x03, 0x00, 0x0c, 0x03, 0x00, 0x0c, 0x03, 0x00, 0x0c,
0x43, 0x20, 0x0c, 0xc6, 0x79, 0x06, 0x86, 0x1f, 0x06, 0x0c, 0x06, 0x03,
0x1c, 0x80, 0x03, 0x78, 0xe0, 0x01, 0xe0, 0x7f, 0x00, 0x80, 0x1f, 0x00 };

UIBitmap smiley1 = UIBitmap(smiley_width, smiley_height, smiley_bits);
UIBitmap smiley2 = UIBitmap(smiley_width, smiley_height, smiley_bits);
UIBitmap smiley3 = UIBitmap(smiley_width, smiley_height, smiley_bits);
UIBitmap smiley4 = UIBitmap(smiley_width, smiley_height, smiley_bits);

UIEnvelope pad1 = UIEnvelope(UIExpansion::None, UIAlignment::Center, UISize(1,1), &smiley1);
UIEnvelope pad2 = UIEnvelope(UIExpansion::Horizontal, UIAlignment::Center, UISize(1,1), &smiley2);
UIEnvelope pad3 = UIEnvelope(UIExpansion::Vertical, UIAlignment::Center, UISize(1,1), &smiley3);
UIEnvelope pad4 = UIEnvelope(UIExpansion::Both, UIAlignment::Center, UISize(1,1), &smiley4);

UIBorder border1 = UIBorder(2,&pad1);
UIBorder border2 = UIBorder(2,&pad2);
UIBorder border3 = UIBorder(2,&pad3);
UIBorder border4 = UIBorder(2,&pad4);

UIEnvelope marg1 = UIEnvelope(UIExpansion::Both, UIAlignment::Center, UISize(1,1), &border1);
UIEnvelope marg2 = UIEnvelope(UIExpansion::Both, UIAlignment::Center, UISize(1,1), &border2, &marg1);
UIEnvelope marg3 = UIEnvelope(UIExpansion::Both, UIAlignment::Center, UISize(1,1), &border3);
UIEnvelope marg4 = UIEnvelope(UIExpansion::Both, UIAlignment::Center, UISize(1,1), &border4, &marg3);

UIRows rows1 = UIRows(&marg2);
UIRows rows2 = UIRows(&marg4,&rows1);

UIColumns cols1 = UIColumns(&rows2);

UIDisplay display = UIDisplay(&cols1);

U8G2_SSD1306_128X64_NONAME_F_HW_I2C screen(U8G2_R2);

void setup() {
Serial.begin(115200);
screen.begin();
display.init(&screen);
}

void loop() {
display.render(&screen);
}
77 changes: 77 additions & 0 deletions src/UIBorder.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// SPDX-License-Identifier: BSD-2-Clause
// (C) 2023 Andrew Burks

#pragma once

#include "Arduino.h"
#include <U8g2lib.h>

#include "UIEnums.h"
#include "UIPoint.h"
#include "UISize.h"
#include "UIArea.h"
#include "UIWidget.h"
#include "UIBorder.h"


UIBorder::UIBorder(UISize thickness,UIWidget* content,UIWidget* next):
UIWidget(next), thickness(thickness), content(content) {
if (content)
content->setParent(this);
}

UIBorder::UIBorder(uint16_t thickness, UIWidget* content,UIWidget* next):
UIBorder(UISize(thickness,thickness),content,next) {}


void UIBorder::layout(U8G2 *display,UIArea *dim) {
UIWidget::layout(display,dim);
if (content) {
dim->debugPrint("border layout");
UIArea contentDim=UIArea(dim);
contentDim.shrink(&thickness);
contentDim.debugPrint("content layout");
content->layout(display,&contentDim);
}
}

void UIBorder::childNeedsRendering(UIWidget *child) {
signalNeedsRendering(); // just pass signal to parent
}

UIArea* UIBorder::render(U8G2 *display,bool force) {
if (force) {
clearFull(display);
dim.debugPrint("border render");
UIArea contentDim=UIArea(dim);
contentDim.shrink(&thickness);
contentDim.debugPrint("content render");

if(content && contentDim.hasArea()){//only draw if there is some area for the content to draw
clip(display);
display->setDrawColor(1);
display->drawBox(dim.left,dim.top,thickness.width,dim.bottom-dim.top);//draw left border
display->drawBox(dim.left,dim.top,dim.right-dim.left,thickness.height);//draw top border
display->drawBox(dim.right-thickness.width,dim.top,thickness.width,dim.bottom-dim.top);//draw right border
display->drawBox(dim.left,dim.bottom-thickness.height,dim.right-dim.left,thickness.height);//draw bottom border
}
if (content)
content->render(display,true);
return &dim;
}
else
return (content?content->render(display,false):&UIArea::EMPTY);
}

void UIBorder::computePreferredSize(U8G2 *display,UISize *preferredSize) {
if (content) {
UISize contentSize=content->preferredSize(display);
preferredSize->set(&contentSize);
}
preferredSize->cumulateBoth(&thickness);
preferredSize->cumulateBoth(&thickness);//double because thickness dimensions only represent half of the total thickness each
preferredSize->debugPrint("preferred size");
}


// end of file
79 changes: 79 additions & 0 deletions src/UIBorder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// SPDX-License-Identifier: BSD-2-Clause
// (C) 2023 Andrew Burks

#pragma once

#include "Arduino.h"
#include <U8g2lib.h>

#include "UIEnums.h"
#include "UIPoint.h"
#include "UISize.h"
#include "UIArea.h"
#include "UIWidget.h"
#include "UIParent.h"


/** Border widget which contains exactly one other widget, changes its representation, and wraps it in a visible frame.
*
* The border can do the following things:
*
* * If the enclosed widget does not spawn the whole display area it is assigned,
* the border can place it with a certain alignment.
* * The border will add a visible frame to the inner widget with a supplied thickness.
* * If the inner widget prefers to be smaller than the space it is allocated,
the frame can be positioned tightly around the widget or loosely around the provided space.
*/
class UIBorder : public UIWidget, public UIParent {
public:

/** Create a border widget.
*
* @param thickness Generate a visible frame of the specified horizontal and vertical thickness around the content widget.
* @param content The content of the border. If empty, the border renders an empty area.
* @param next Next widget on the same level as the border.
*/
UIBorder(UISize thickness ,UIWidget* content=nullptr,UIWidget* next=nullptr);

/** Create a border widget.
*
* @param thickness Generate a visible frame of the specified uniform thickness around the content widget.
* @param content The content of the border. If empty, the border renders an empty area.
* @param next Next widget on the same level as the border.
*/
UIBorder(uint16_t thickness, UIWidget* content=nullptr,UIWidget* next=nullptr);


/** Layout the border.
*
* This includes shaping the content according to all the constraints.
*/
void layout(U8G2 *display,UIArea *dim);

/** Render the frame - which also renders the content if it exists. */
UIArea* render(U8G2 *display,bool force);

/** Called by the child of this frame to indicate that it wants to be rendered. */
void childNeedsRendering(UIWidget *child);

protected:

/** Compute the preferred size which is determined by the content and the frame thickness. */
void computePreferredSize(U8G2 *display,UISize *preferredSize);

/** Compute the area representing the outside of the border frame given the allocated area of this widget and its content. */
void computeOuterFrame(UIArea* allocatedArea, UIArea* contentArea, UIArea* outerFrame);

private:


/** Border thickness, horizontal lines may be thicker than vertical lines. */
UISize thickness;

/** Reference to the content widget of the border. */
UIWidget* content;


};

// end of file
1 change: 1 addition & 0 deletions src/UiUiUi.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "UIEnvelope.h"
#include "UIProgressBar.h"
#include "UIBitmap.h"
#include "UIBorder.h"

// Widget groups
#include "UIWidgetGroup.h"
Expand Down

0 comments on commit f462ede

Please sign in to comment.