diff --git a/blitbuffer.c b/blitbuffer.c index c8a51de7f..8ea96a7a6 100644 --- a/blitbuffer.c +++ b/blitbuffer.c @@ -366,6 +366,63 @@ static int paintRect(lua_State *L) { return 0; } +static int invertRect(lua_State *L) { + BlitBuffer *dst = (BlitBuffer*) luaL_checkudata(L, 1, "blitbuffer"); + int x = luaL_checkint(L, 2); + int y = luaL_checkint(L, 3); + int w = luaL_checkint(L, 4); + int h = luaL_checkint(L, 5); + uint8_t *dstptr; + + int cy, cx; + if(w <= 0 || h <= 0 || x >= dst->w || y >= dst->h) { + return 0; + } + if(x + w > dst->w) { + w = dst->w - x; + } + if(y + h > dst->h) { + h = dst->h - y; + } + + if(x & 1) { + /* This will invert the leftmost column + * in the case when x is odd. After this, + * x will become even. */ + dstptr = (uint8_t*)(dst->data + + y * dst->pitch + + x / 2); + for(cy = 0; cy < h; cy++) { + *dstptr ^= 0x0F; + dstptr += dst->pitch; + } + x++; + w--; + } + dstptr = (uint8_t*)(dst->data + + y * dst->pitch + + x / 2); + for(cy = 0; cy < h; cy++) { + for(cx = 0; cx < w/2; cx++) { + *(dstptr+cx) ^= 0xFF; + } + dstptr += dst->pitch; + } + if(w & 1) { + /* This will invert the rightmost column + * in the case when (w & 1) && !(x & 1) or + * !(w & 1) && (x & 1). */ + dstptr = (uint8_t*)(dst->data + + y * dst->pitch + + (x + w) / 2); + for(cy = 0; cy < h; cy++) { + *dstptr ^= 0xF0; + dstptr += dst->pitch; + } + } + return 0; +} + static const struct luaL_reg blitbuffer_func[] = { {"new", newBlitBuffer}, {NULL, NULL} @@ -378,6 +435,7 @@ static const struct luaL_reg blitbuffer_meth[] = { {"addblitFrom", addblitToBuffer}, {"blitFullFrom", blitFullToBuffer}, {"paintRect", paintRect}, + {"invertRect", invertRect}, {"free", freeBlitBuffer}, {"__gc", freeBlitBuffer}, {NULL, NULL} diff --git a/graphics.lua b/graphics.lua index 1ebb13cce..f12510252 100644 --- a/graphics.lua +++ b/graphics.lua @@ -6,6 +6,7 @@ blitbuffer.paintBorder = function (bb, x, y, w, h, bw, c) bb:paintRect(x+w-bw, y+bw, bw, h - 2*bw, c) end + --[[ Draw a progress bar according to following args: @@ -27,3 +28,83 @@ blitbuffer.progressBar = function (bb, x, y, w, h, fb.bb:paintRect(x+load_m_w, y+load_m_h, (w-2*load_m_w)*load_percent, (h-2*load_m_h), c) end + + + +------------------------------------------------ +-- Start of Cursor class +------------------------------------------------ + +Cursor = { + x_pos = 0, + y_pos = 0, + --color = 15, + h = 10, + w = nil, + line_w = nil, +} + +function Cursor:new(o) + o = o or {} + o.x_pos = o.x_pos or self.x_pos + o.y_pos = o.y_pos or self.y_pos + o.h = o.h or self.h + + o.w = o.h / 3 + o.line_w = math.floor(o.h / 10) + + setmetatable(o, self) + self.__index = self + return o +end + +function Cursor:_draw(x, y) + local body_h = self.h - self.line_w + -- paint upper horizontal line + fb.bb:invertRect(x, y, self.w, self.line_w/2) + -- paint middle vertical line + fb.bb:invertRect(x+(self.w/2)-(self.line_w/2), y+self.line_w/2, + self.line_w, body_h) + -- paint lower horizontal line + fb.bb:invertRect(x, y+body_h+self.line_w/2, self.w, self.line_w/2) +end + +function Cursor:draw() + self:_draw(self.x_pos, self.y_pos) +end + +function Cursor:clear() + self:_draw(self.x_pos, self.y_pos) +end + +function Cursor:move(x_off, y_off) + self.x_pos = self.x_pos + x_off + self.y_pos = self.y_pos + y_off +end + +function Cursor:moveHorizontal(x_off) + self.x_pos = self.x_pos + x_off +end + +function Cursor:moveVertical(x_off) + self.y_pos = self.y_pos + y_off +end + +function Cursor:moveAndDraw(x_off, y_off) + self:clear() + self:move(x_off, y_off) + self:draw() +end + +function Cursor:moveHorizontalAndDraw(x_off) + self:clear() + self:move(x_off, 0) + self:draw() +end + +function Cursor:moveVerticalAndDraw(y_off) + self:clear() + self:move(0, y_off) + self:draw() +end + diff --git a/inputbox.lua b/inputbox.lua index 6e3fc6667..65321e0d6 100644 --- a/inputbox.lua +++ b/inputbox.lua @@ -4,6 +4,8 @@ require "graphics" InputBox = { -- Class vars: + h = 100, + input_slot_w = nil, input_start_x = 145, input_start_y = nil, input_cur_x = nil, -- points to the start of next input pos @@ -15,44 +17,75 @@ InputBox = { shiftmode = false, altmode = false, + cursor = nil, + -- font for displaying input content + -- we have to use mono here for better distance controlling face = freetype.newBuiltinFace("mono", 25), fhash = "m25", fheight = 25, - fwidth = 16, + fwidth = 15, } -function InputBox:setDefaultInput(text) - self.input_string = "" - self:addString(text) - --self.input_cur_x = self.input_start_x + (string.len(text) * self.fwidth) - --self.input_string = text -end - -function InputBox:addString(str) - for i = 1, #str do - self:addChar(str:sub(i,i)) - end +function InputBox:refreshText() + -- clear previous painted text + fb.bb:paintRect(140, self.input_start_y-19, + self.input_slot_w, self.fheight, self.input_bg) + -- paint new text + renderUtf8Text(fb.bb, self.input_start_x, self.input_start_y, + self.face, self.fhash, + self.input_string, 0) end function InputBox:addChar(char) - renderUtf8Text(fb.bb, self.input_cur_x, self.input_start_y, self.face, self.fhash, - char, true) - fb:refresh(1, self.input_cur_x, self.input_start_y-19, self.fwidth, self.fheight) + self.cursor:clear() + + -- draw new text + local cur_index = (self.cursor.x_pos + 3 - self.input_start_x) + / self.fwidth + self.input_string = self.input_string:sub(0,cur_index)..char.. + self.input_string:sub(cur_index+1) + self:refreshText() self.input_cur_x = self.input_cur_x + self.fwidth - self.input_string = self.input_string .. char + -- draw new cursor + self.cursor:moveHorizontal(self.fwidth) + self.cursor:draw() + + fb:refresh(1, self.input_start_x-5, self.input_start_y-25, + self.input_slot_w, self.h-25) end function InputBox:delChar() if self.input_start_x == self.input_cur_x then return end + + self.cursor:clear() + + -- draw new text + local cur_index = (self.cursor.x_pos + 3 - self.input_start_x) + / self.fwidth + self.input_string = self.input_string:sub(0,cur_index-1).. + self.input_string:sub(cur_index+1, -1) + self:refreshText() self.input_cur_x = self.input_cur_x - self.fwidth - --fill last character with blank rectangle - fb.bb:paintRect(self.input_cur_x, self.input_start_y-19, - self.fwidth, self.fheight, self.input_bg) - fb:refresh(1, self.input_cur_x, self.input_start_y-19, self.fwidth, self.fheight) - self.input_string = self.input_string:sub(0,-2) + -- draw new cursor + self.cursor:moveHorizontal(-self.fwidth) + self.cursor:draw() + + fb:refresh(1, self.input_start_x-5, self.input_start_y-25, + self.input_slot_w, self.h-25) +end + +function InputBox:clearText() + self.cursor:clear() + self.input_string = "" + self:refreshText() + self.cursor.x_pos = self.input_start_x - 3 + self.cursor:draw() + + fb:refresh(1, self.input_start_x-5, self.input_start_y-25, + self.input_slot_w, self.h-25) end function InputBox:drawBox(ypos, w, h, title) @@ -66,35 +99,40 @@ function InputBox:drawBox(ypos, w, h, title) end ---[[ - || d_text default to nil (used to set default text in input slot) ---]] +---------------------------------------------------------------------- +-- InputBox:input() +-- +-- @title: input prompt for the box +-- @d_text: default to nil (used to set default text in input slot) +---------------------------------------------------------------------- function InputBox:input(ypos, height, title, d_text) - local pagedirty = true -- do some initilization + self.h = height self.input_start_y = ypos + 35 self.input_cur_x = self.input_start_x + self.input_slot_w = fb.bb:getWidth() - 170 - if d_text then -- if specified default text, draw it - w = fb.bb:getWidth() - 40 - h = height - 45 - self:drawBox(ypos, w, h, title) - self:setDefaultInput(d_text) - fb:refresh(1, 20, ypos, w, h) - pagedirty = false - else -- otherwise, leave the draw task to the main loop - self.input_string = "" + self.cursor = Cursor:new { + x_pos = self.input_start_x - 3, + y_pos = ypos + 13, + h = 30, + } + + + -- draw box and content + w = fb.bb:getWidth() - 40 + h = height - 45 + self:drawBox(ypos, w, h, title) + if d_text then + self.input_string = d_text + self.input_cur_x = self.input_cur_x + (self.fwidth * d_text:len()) + self.cursor.x_pos = self.cursor.x_pos + (self.fwidth * d_text:len()) + self:refreshText() end + self.cursor:draw() + fb:refresh(1, 20, ypos, w, h) while true do - if pagedirty then - w = fb.bb:getWidth() - 40 - h = height - 45 - self:drawBox(ypos, w, h, title) - fb:refresh(1, 20, ypos, w, h) - pagedirty = false - end - local ev = input.waitForEvent() ev.code = adjustKeyEvents(ev) if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then @@ -177,14 +215,30 @@ function InputBox:input(ypos, height, title, d_text) self:addChar(" ") elseif ev.code == KEY_PGFWD then elseif ev.code == KEY_PGBCK then + elseif ev.code == KEY_FW_LEFT then + if (self.cursor.x_pos + 3) > self.input_start_x then + self.cursor:moveHorizontalAndDraw(-self.fwidth) + fb:refresh(1, self.input_start_x-5, ypos, + self.input_slot_w, h) + end + elseif ev.code == KEY_FW_RIGHT then + if (self.cursor.x_pos + 3) < self.input_cur_x then + self.cursor:moveHorizontalAndDraw(self.fwidth) + fb:refresh(1,self.input_start_x-5, ypos, + self.input_slot_w, h) + end elseif ev.code == KEY_ENTER or ev.code == KEY_FW_PRESS then if self.input_string == "" then self.input_string = nil end break elseif ev.code == KEY_DEL then - self:delChar() - elseif ev.code == KEY_BACK then + if Keys.shiftmode then + self:clearText() + else + self:delChar() + end + elseif ev.code == KEY_BACK or ev.code == KEY_HOME then self.input_string = nil break end @@ -195,5 +249,7 @@ function InputBox:input(ypos, height, title, d_text) end -- if end -- while - return self.input_string + local return_str = self.input_string + self.input_string = "" + return return_str end