ide: cosmetics, GridCtrl: Selection refactored to follow spreadsheet model

git-svn-id: svn://ultimatepp.org/upp/trunk@15558 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2020-12-01 13:03:42 +00:00
parent 77f3a86282
commit a01614cb42
13 changed files with 1610 additions and 1626 deletions

View file

@ -208,6 +208,8 @@ CtrlFrame& BottomSeparatorFrame();
CtrlFrame& LeftSeparatorFrame();
CtrlFrame& RightSeparatorFrame();
CtrlFrame& RightGapFrame();
void LayoutFrameLeft(Rect& r, Ctrl *ctrl, int cx);
void LayoutFrameRight(Rect& r, Ctrl *ctrl, int cx);
void LayoutFrameTop(Rect& r, Ctrl *ctrl, int cy);

View file

@ -107,11 +107,21 @@ class RightSeparatorFrameCls : public CtrlFrame {
virtual void FrameAddSize(Size& sz) { sz.cx += 2; }
};
class RightGapFrameCls : public CtrlFrame {
virtual void FrameLayout(Rect& r) { r.right -= DPI(2); }
virtual void FramePaint(Draw& w, const Rect& r) {
w.DrawRect(r.right - DPI(2), r.top, DPI(2), r.Height(), SColorFace());
}
virtual void FrameAddSize(Size& sz) { sz.cx += DPI(2); }
};
CtrlFrame& BottomSeparatorFrame() { return Single<BottomSeparatorFrameCls>(); }
CtrlFrame& TopSeparatorFrame() { return Single<TopSeparatorFrameCls>(); }
CtrlFrame& RightSeparatorFrame() { return Single<RightSeparatorFrameCls>(); }
CtrlFrame& LeftSeparatorFrame() { return Single<LeftSeparatorFrameCls>(); }
CtrlFrame& RightGapFrame() { return Single<RightGapFrameCls>(); }
CH_INT(FrameButtonWidth, DPI(17));
CH_INT(ScrollBarArrowSize, FrameButtonWidth());

File diff suppressed because it is too large Load diff

View file

@ -949,7 +949,6 @@ class GridCtrl : public Ctrl
bool isedit:1;
int genr_ctrls;
bool edit_ctrls:1;
bool shiftmode:1;
bool recalc_cols;
bool recalc_rows;
bool cancel_update_cell:1;
@ -962,7 +961,6 @@ class GridCtrl : public Ctrl
bool cancel_move:1;
bool mouse_move:1;
bool is_clipboard:1;
bool selecting:1;
bool enabled:1;
bool call_whenchangecol:1;
@ -1024,14 +1022,15 @@ class GridCtrl : public Ctrl
/* Points */
Point curpos; // cursor position
Point anchor; // selection anchor
Point oldpos;
Point curpos;
Point oldcur;
Point curid;
Point livecur;
Point ctrlpos;
Point ctrlid;
Point shiftpos;
Point leftpnt;
Size osz;
@ -1389,6 +1388,7 @@ class GridCtrl : public Ctrl
int GetMouseRow(Point &p, bool relative = true, bool fixed = false, bool full = true);
int GetMouseCol(Point &p, bool relative = true, bool fixed = false, bool full = true);
Point GetPos(Point p);
void UpdateCursor();
@ -1547,8 +1547,6 @@ class GridCtrl : public Ctrl
void DoSelectAll();
void DoSwapUp();
void DoSwapDown();
void DoShiftSelect();
void DoCtrlSelect();
void DoGoBegin();
void DoGoEnd();
void DoGoNext();
@ -1713,6 +1711,7 @@ class GridCtrl : public Ctrl
void SelectCount(int i, int cnt = 1, bool sel = true);
void SelectRange(int from, int to, bool sel = true);
void SelectRange(Point from, Point to, bool sel = true, bool fullrow = false);
void SelectRange(const Rect& r, bool sel , bool fullrow );
void ShiftSelect(int from, int to);
void ShiftSelect(Point from, Point to);
void SelectInverse(int from, int to);

View file

@ -10,6 +10,10 @@ uses(GRIDSQL) Sql;
file
GridCtrl.h,
GridCtrl.cpp,
GridKey.cpp,
GridSelect.cpp,
GridMouse.cpp,
GridPaint.cpp,
GridDisplay.h,
GridDisplay.cpp,
GridText.cpp,

216
uppsrc/GridCtrl/GridKey.cpp Normal file
View file

@ -0,0 +1,216 @@
#include "GridCtrl.h"
namespace Upp {
bool GridCtrl::Key(dword key, int)
{
auto NewAnchor = [&] {
ClearSelection();
anchor = curpos;
};
auto NewSelection = [&] {
ClearSelection();
if(IsValidCursor(anchor) && IsValidCursor(curpos))
SelectRange(Rect(anchor, curpos), true, select_row);
Refresh();
};
if(!IsReadOnly())
switch(key)
{
case K_ENTER:
ClearSelection();
WhenEnter();
#ifdef LOG_CALLBACKS
LGR(2, "WhenEnter()");
#endif
if(enter_like_tab)
return TabKey(true);
else if(!SwitchEdit())
return true;
/*
if(th.IsSorted())
{
th.Multisort();
Refresh();
}*/
NewAnchor();
return true;
case K_ESCAPE:
{
bool quit = true;
if(search_string.GetCount() > 0)
{
ClearFound();
quit = false;
}
else if(HasCtrls())
{
bool canceled = CancelEdit();
quit = !canceled;
}
if(quit)
{
WhenEscape();
return false;
}
else
return true;
}
case K_SHIFT|K_LEFT:
GoLeft();
NewSelection();
return true;
case K_SHIFT|K_RIGHT:
GoRight();
NewSelection();
return true;
case K_SHIFT|K_UP:
GoPrev();
NewSelection();
return true;
case K_SHIFT|K_DOWN:
GoNext();
NewSelection();
return true;
case K_SHIFT|K_PAGEUP:
GoPageUp();
NewSelection();
return true;
case K_SHIFT|K_PAGEDOWN:
GoPageDn();
NewSelection();
return true;
case K_SHIFT_HOME:
GoBegin();
NewSelection();
return true;
case K_SHIFT_END:
GoEnd();
NewSelection();
return true;
case K_UP:
GoPrev();
NewAnchor();
return true;
case K_DOWN:
GoNext();
NewAnchor();
return true;
case K_LEFT:
GoLeft();
NewAnchor();
return true;
case K_RIGHT:
GoRight();
NewAnchor();
return true;
case K_HOME:
case K_CTRL_HOME:
case K_CTRL_PAGEUP:
GoBegin();
NewAnchor();
return true;
case K_END:
case K_CTRL_END:
case K_CTRL_PAGEDOWN:
GoEnd();
NewAnchor();
return true;
case K_PAGEUP:
GoPageUp();
NewAnchor();
return true;
case K_PAGEDOWN:
GoPageDn();
NewAnchor();
return true;
case K_TAB:
return TabKey(false);
case K_SHIFT|K_TAB:
if(HasCtrls())
{
bool isprev = ShowPrevCtrl();
return focused_ctrl ? true : isprev;
}
else if(tab_changes_row)
{
bool isprev = false;
if(select_row)
isprev = GoPrev();
else
isprev = GoLeft();
ClearSelection();
return isprev;
}
else
return false;
case K_CTRL|K_F:
if(searching)
{
find.SetFocus();
return true;
}
else
return false;
case K_BACKSPACE:
{
if(searching)
{
int cnt = search_string.GetCount();
if(cnt > 0)
{
search_string.Remove(cnt - 1);
find <<= search_string;
ShowMatchedRows(search_string);
}
return true;
}
else
return false;
}
case K_F3:
if(rowfnd >= 0)
{
for(int i = rowfnd + 1; i < total_rows; i++)
{
if(vitems[i].IsFound())
{
rowfnd = i;
SetCursor0(i);
CenterCursor();
WhenSearchCursor();
return true;
}
}
for(int i = fixed_rows; i < rowfnd; i++)
{
if(vitems[i].IsFound())
{
rowfnd = i;
SetCursor0(i);
CenterCursor();
WhenSearchCursor();
return true;
}
}
return true;
}
return false;
case K_CTRL_W:
WriteClipboardText(GetColumnWidths());
return true;
default:
if(searching && !isedit && Search(key))
return true;
}
return MenuBar::Scan(WhenMenuBar, key);
}
};

View file

@ -0,0 +1,577 @@
#include "GridCtrl.h"
namespace Upp {
int GridCtrl::GetMouseCol(Point &p, bool relative, bool fixed, bool full)
{
if(!full && p.x < fixed_width)
return -1;
int dx = 0;
if(relative)
dx += sbx;
int first_col = fixed ? 0 : max(firstVisCol, fixed_cols);
int last_col = max(lastVisCol, fixed_cols - 1);
if(!fixed && last_col >= total_cols)
return -1;
for(int i = first_col; i <= last_col; i++)
{
if(p.x >= hitems[i].nLeft(dx) &&
p.x < hitems[i].nRight(dx))
return i;
}
return -1;
}
int GridCtrl::GetMouseRow(Point &p, bool relative, bool fixed, bool full)
{
if(!full && p.y < fixed_height)
return -1;
int dy = 0;
if(relative)
dy += sby;
int first_row = fixed ? 0 : max(firstVisRow, fixed_rows);
int last_row = max(lastVisRow, fixed_rows - 1);
if(!fixed && last_row >= total_rows)
return -1;
for(int i = first_row; i <= last_row; i++)
{
if(p.y >= vitems[i].nTop(dy) &&
p.y < vitems[i].nBottom(dy))
return i;
}
return -1;
}
Point GridCtrl::GetPos(Point p)
{
return Point(GetMouseCol(p, true, false), GetMouseRow(p, true, false));
}
void GridCtrl::LeftDown(Point p, dword keyflags)
{
//popup.Close();
SetCapture();
leftpnt = p;
just_clicked = true;
fixed_top_click = p.x >= fixed_width && p.y < fixed_height;
fixed_left_click = p.x < fixed_width && p.y >= fixed_height;
fixed_click = fixed_top_click || fixed_left_click;
top_click = p.y < fixed_height;
resizing = curResizeCol || curResizeRow;
if(resizing)
{
popup.Close();
splitCol = curSplitCol;
splitRow = curSplitRow;
resizeCol = curResizeCol;
resizeRow = curResizeRow;
Split(GS_DOWN);
return;
}
else if(fixed_click)
{
moveCol = oldMoveCol = GetMouseCol(p, fixed_top_click, 1);
moveRow = oldMoveRow = GetMouseRow(p, fixed_left_click, 1);
return;
}
SetFocus();
if(IsEmpty() || IsReadOnly())
return;
bool is_shift = keyflags & K_SHIFT;
bool is_ctrl = keyflags & K_CTRL;
Point oldcur = curpos;
CurState cs = SetCursor0(p, CU_MOUSE | CU_HIDECTRLS);
bool state_change = cs.IsValid() && !cs.IsNew() && (is_ctrl || is_shift);
if(!cs.IsAccepted() && !state_change)
return;
anchor = curpos;
if(cs || state_change) {
moveCol = curpos.x;
moveRow = curpos.y;
if(keyflags & K_CTRL) {
SelectRange(oldcur, oldcur, !IsSelected(curpos.y, curpos.y), select_row);
SelectRange(curpos, curpos, !IsSelected(curpos.y, curpos.y), select_row);
}
else {
ClearSelection();
if((keyflags & K_SHIFT) && multi_select && IsValidCursor(oldcur)) {
SetCursor0(oldcur, CU_HIDECTRLS);
Refresh();
}
}
}
#ifdef LOG_CALLBACKS
//LGR(2, "WhenLeftClick()");
#endif
WhenLeftClick();
if(editing && one_click_edit && cs.IsValid() ) //&& IsRowEditable() ?
StartEdit();
else
RebuildToolBar();
SetCapture();
}
void GridCtrl::MouseMove(Point p, dword keyflags)
{
mouse_move = true;
if(resizing)
{
int si, lp, mp, off;
RectItems *its;
static int sub = 0;
if(resizeCol)
{
mp = p.x;
lp = leftpnt.x;
si = splitCol;
its = &hitems;
bool top = fixed_top_click || (!fixed_left_click && full_col_resizing);
off = top ? sbx : 0;
}
else
{
mp = p.y;
lp = leftpnt.y;
si = splitRow;
its = &vitems;
bool left = fixed_left_click || (!fixed_top_click && full_row_resizing);
off = left ? sby : 0;
}
int right = (*its)[si].nRight(off);
if(just_clicked)
{
sub = right - lp;
just_clicked = false;
}
if(SetDiffItemSize(resizeCol, *its, si, mp - right + sub))
{
Split(GS_MOVE);
}
return;
}
else if(fixed_click)
{
if((fixed_top_click && !moving_cols) ||
(fixed_left_click && !moving_rows) ||
moveCol < 0 || moveRow < 0)
return;
if(!moving_header)
{
int diffx = p.x - leftpnt.x;
int diffy = p.y - leftpnt.y;
if(abs(diffx) < 5 && abs(diffy) < 5)
return;
p -= Point(diffx, diffy);
moving_header = true;
int idx = hitems[moveCol].id;
int idy = vitems[moveRow].id;
pophdr.val = idy > 0 ? GetConvertedColumn(moveCol, items[idy][idx].val) : items[idy][idx].val;
if(fixed_top_click)
{
pophdr.sortmode = hitems[moveCol].sortmode;
pophdr.sortcol = hitems[moveCol].sortcol;
pophdr.sortcnt = sortOrder.GetCount();
UpdateHighlighting(GS_POPUP, p);
}
else
{
pophdr.sortmode = 0;
pophdr.sortcol = -1;
pophdr.sortcnt = 0;
}
dx = hitems[moveCol].nLeft(fixed_top_click ? sbx : 0) - p.x;
dy = vitems[moveRow].nTop(fixed_left_click ? sby : 0) - p.y;
}
Point pt = p + GetScreenRect().TopLeft() + GetBarOffset();
pophdr.display = display;
pophdr.chameleon = chameleon;
pophdr.PopUp(this, pt.x + dx, pt.y + dy, hitems[moveCol].nWidth(), vitems[moveRow].nHeight());
if(fixed_top_click && curSplitCol != oldMoveCol)
{
moving_allowed = CanMoveCol(moveCol, curSplitCol);
RefreshTop();
//Refresh(oldMoveCol >= 0 ? hitems[oldMoveCol].nRight(sbx) : 0, 0, hitems[curSplitCol].nRight(sbx), fixed_height);
oldMoveCol = curSplitCol;
}
if(fixed_left_click && curSplitRow != oldMoveRow)
{
Refresh(0, 0, fixed_width, fixed_height);
RefreshLeft();
oldMoveRow = curSplitRow;
}
return;
}
if(leftpnt != p && p.y < fixed_height)
{
UpdateHighlighting(GS_MOVE, p);
}
if(live_cursor && popup.IsOpen())
{
LG(2, "MouseMove:LiveCursor");
if(IsMouseBody(p))
SetCursor0(p, CU_MOUSE | CU_HIGHLIGHT);
else
SetCursor0(-1, -1, CU_HIGHLIGHT);
}
if(HasCapture())
{
if(!moving_body)
{
anchor = GetPos(p);
Refresh();
return;
/* if(keyflags & K_SHIFT)
{
if(SetCursor0(p, CU_MOUSE))
DoShiftSelect();
return;
}
bool select = true;
if(select_row && !multi_select)
select = false;
if(select && (keyflags & K_CTRL))
{
if(SetCursor0(p, CU_MOUSE))
// DoCtrlSelect();
return;
}*/
}
if(moveCol < 0 || moveRow < 0)
return;
if(!dragging)
return;
if(!moving_body)
{
popup.Close();
if(!top_click && valid_cursor &&
p.x < total_width &&
p.y < total_height &&
(abs(p.y - leftpnt.y) > 5 ||
abs(p.x - leftpnt.x) > 5))
moving_body = true;
oldMoveRow = -1;
}
else
{
Point pt = p + GetScreenRect().TopLeft();
int row = curSplitRow - fixed_rows + 2;
if(select_row)
{
int count = max(1, selected_rows);
if(vitems[curpos.y].IsSelect())
popup.val = Format(t_("Moving selection (%d %s) before row %d"), count, count == 1 ? t_("row") : t_("rows"), row);
else
popup.val = Format(t_("Moving row %d before row %d"), curpos.y - fixed_rows + 1, row);
}
else
{
int count = max(1, selected_items);
popup.val = Format(t_("Moving %d %s before row %d"), count, count == 1 ? t_("cell") : t_("cells"), row);
}
int px = pt.x + 15;
int py = pt.y + GD_ROW_HEIGHT;
popup.gd = display;
popup.gd->row = 0;
popup.gd->col = 0;
popup.fg = SColorText;
popup.bg = SColorPaper;
popup.fnt = StdFont();
popup.style = 0;
popup.PopUp(this, px, py, GetTextSize((String) popup.val, StdFont()).cx + 10, GD_ROW_HEIGHT);
SetFocus();
if(curSplitRow != oldMoveRow || scrollLeftRight)
{
int dy = sby;
if(oldMoveRow >= 0)
Refresh(Rect(0, vitems[oldMoveRow].nBottom(dy) - 5, GetSize().cx, vitems[oldMoveRow].nBottom(dy) + 5));
else
Refresh(Rect(0, 0, GetSize().cx, 5));
if(curSplitRow >= 0)
Refresh(Rect(0, vitems[curSplitRow].nBottom(dy) - 5, GetSize().cx, vitems[curSplitRow].nBottom(dy) + 5));
else
Refresh(Rect(0, 0, GetSize().cx, 5));
oldMoveRow = curSplitRow;
popup.Refresh();
scrollLeftRight = false;
}
}
}
else
SyncPopup();
}
void GridCtrl::LeftUp(Point p, dword keyflags)
{
LG(0, "LeftUp");
bool capture = HasCapture();
ReleaseCapture();
Refresh();
fixed_click = false;
UpdateHighlighting(resizing ? GS_MOVE : GS_UP, p);
if(moving_header)
{
LG(0, "moving_header");
pophdr.Close();
moving_header = false;
if(fixed_top_click)
MoveCol(moveCol, curSplitCol);
else
MoveRow(moveRow, curSplitRow);
if(focused_ctrl)
focused_ctrl->SetFocus();
fixed_top_click = false;
fixed_left_click = false;
return;
}
if(resizing)
{
Split(GS_UP);
resizeCol = resizeRow = resizing = false;
return;
}
if(fixed_top_click && sorting && Distance(leftpnt, p) < 3)
{
int i = GetMouseRow(leftpnt, false, true);
int j = GetMouseCol(leftpnt, true, false);
if(j >= fixed_cols && i == 0 && hitems[i].sortable)
{
int newSortCol = hitems[j].id;
if(sorting_multicol && (keyflags & K_CTRL))
{
int colidx = InMultisort(newSortCol);
if(colidx < 0)
sortOrder.Add(newSortCol);
int cnt = sortOrder.GetCount();
hitems[j].ChangeSortMode(newSortCol == sortOrder[cnt - 1]);
if(colidx >= 0)
{
if(hitems[j].sortmode == 0)
{
sortOrder.Remove(colidx);
cnt--;
}
if(WhenSort)
WhenSort();
else
{
if(hitems[j].sortmode > 0 && colidx == cnt - 1)
GSort();
else
Multisort();
}
}
else
{
hitems[j].sortcol = cnt;
if(WhenSort)
WhenSort();
else
GSort();
}
}
else
{
if(sortCol >= 0 && sortCol != newSortCol)
{
int idx = GetIdCol(sortCol, true);
hitems[idx].sortmode = 0;
}
ClearMultisort(1);
hitems[j].ChangeSortMode();
hitems[j].sortcol = 1;
if(hitems[j].sortmode == 0)
sortCol = -1;
else
sortCol = newSortCol;
sortOrder.Add(newSortCol);
if(WhenSort)
WhenSort();
else
GSort(newSortCol, hitems[j].sortmode, fixed_rows);
}
UpdateCursor();
Repaint(false, true);
if(WhenSorted)
WhenSorted();
}
}
if(moving_body)
{
popup.Close();
moving_body = false;
MoveRows(curSplitRow + 1, !vitems[curpos.y].IsSelect());
return;
}
if(IsValidCursor(anchor) && IsValidCursor(curpos))
SelectRange(Rect(anchor, curpos), true, select_row);
anchor = curpos;
}
void GridCtrl::LeftDouble(Point p, dword keyflags)
{
LG(0, "LeftDouble");
if(full_col_resizing && curSplitCol >= 0)
return;
if(full_row_resizing && curSplitRow >= 0)
return;
if(IsEmpty() || !IsMouseBody(p) || IsReadOnly())
return;
if(keyflags & K_SHIFT || keyflags & K_CTRL)
return;
if(!valid_cursor)
return;
if(editing)
StartEdit();
if(!IsCtrl(curpos))
{
popup.Close();
#ifdef LOG_CALLBACKS
LGR(2, "WhenLeftDouble()");
#endif
WhenLeftDouble();
}
}
void GridCtrl::LeftRepeat(Point p, dword keyflags)
{
if(!moving_header && !resizeCol && !resizeRow)
MouseAccel(p, resize_col_mode == 0, resize_row_mode == 0, keyflags);
}
void GridCtrl::RightDown(Point p, dword keyflags)
{
if(IsReadOnly())
return;
if(total_rows > fixed_rows)
{
if(!EndEdit())
return;
SetCursor0(p, CU_MOUSE);
}
RebuildToolBar();
SetFocus(); //jak nie bedzie menu to fokous zostanie na danym wierszu
MenuBar::Execute(WhenMenuBar);
anchor = curpos;
}
void GridCtrl::MouseLeave()
{
if(live_cursor)
{
LG(2, "MouseLeave:LiveCursor");
SetCursor0(-1, -1, CU_HIGHLIGHT);
}
UpdateHighlighting(GS_BORDER, Point(0, 0));
oldSplitCol = -1;
oldSplitRow = -1;
//popup.Close();
}
void GridCtrl::MouseWheel(Point p, int zdelta, dword keyflags)
{
if(resize_row_mode == 0)
{
sby.Set(sby - zdelta / 4);
}
}
};

View file

@ -0,0 +1,513 @@
#include "GridCtrl.h"
namespace Upp {
void GridCtrl::Paint(Draw &w)
{
static int paintcnt = 0;
Font stdfont(StdFont());
Size sz = GetSize();
Rect rc = Rect(sz); //w.GetClip() - it always returns view rect now. bug??
if(!ready)
{
w.DrawRect(rc, SColorPaper);
return;
}
int i, j, cx, cy, x, y;
bool skip;
Rect r;
LG(0, "---- Paint(%d)", ++paintcnt);
if(total_cols <= 1 || total_rows == 0)
{
LG(0, "---- Paint(%d) Empty.", paintcnt);
w.DrawRect(sz, SColorPaper);
return;
}
if(UpdateCols() || UpdateRows())
UpdateSizes();
if(firstCol < 0) firstCol = GetFirstVisCol(fixed_width);
if(firstRow < 0) firstRow = GetFirstVisRow(fixed_height);
LG(0, "firstCol %d", firstCol);
LG(0, "firstRow %d", firstRow);
int en = IsShowEnabled() ? 0 : GD::READONLY;
//---------------------------------------------------------------------------------------
if(fixed_width > 0 && fixed_height > 0)
{
w.Clip(0, 0, fixed_width, fixed_height);
dword style = chameleon ? GD::CHAMELEON : 0;
display->PaintFixed(w, 1, 1, 0, 0, fixed_width, fixed_height,
Value(""),
style, stdfont, false, false,
0, -1, 0,
true);
w.End();
}
r.Set(fixed_width, 0, sz.cx, summary_row ? sz.cy : fixed_height);
if(w.IsPainting(r) && total_cols > 1)
{
LG(0, "Top header");
w.Clip(r);
x = hitems[total_cols - 1].nRight(sbx);
int rx = x;
int firstcol = indicator ? 0 : (fixed_cols > 1 ? 1 : firstVisCol);
if(firstCol < 0) firstCol = 0;
int jfc = chameleon ? 0 : firstCol;
for(i = 0; i < fixed_rows; i++)
{
for(j = jfc; j < total_cols; j++)
{
ItemRect& hi = hitems[j];
if(hi.hidden)
continue;
int jj = j;
Item &it = GetItemSize(i, j, x, y, cx, cy, skip, true, false);
if(skip)
continue;
if(x >= rc.right)
break;
if(w.IsPainting(x, y, cx, cy))
{
GridDisplay * gd = it.display ? it.display : display;
dword style = hi.style | hi.halign;
if(i > 0) style &= ~GD::HIGHLIGHT;
if(chameleon)
style |= GD::CHAMELEON;
Font fnt(stdfont);
gd->SetLeftImage(hi.img);
gd->ReverseSortIcon(reverse_sort_icon);
gd->PaintFixed(w, jj == firstcol, i == 0, x, y, cx, cy,
i == 0 ? it.val : GetConvertedColumn(hi.id, it.val),
style | en, IsNull(hi.hfnt) ? fnt : hi.hfnt, false, false,
i == 0 ? hi.sortmode : 0,
hi.sortcol,
sortOrder.GetCount(),
true);
it.rcx = gd->real_size.cx;
it.rcy = gd->real_size.cy;
}
if(summary_row && i == 0)
{
cy = GD_HDR_HEIGHT;
y = sz.cy - cy;
if(w.IsPainting(x, y, cx, cy))
{
Item &it = summary[hi.id];
GridDisplay * gd = it.display ? it.display : display;
dword style = en | hi.halign;
if(chameleon)
style |= GD::CHAMELEON;
String s;
if(hi.sop != SOP_NONE && !hi.sopfrm.IsEmpty() && !IsNull(it.val))
s = Format(hi.sopfrm, it.val);
else
s = IsString(it.val) ? it.val : StdConvert().Format(it.val);
gd->SetLeftImage(Null);
//gd->PaintFixed(w, jj == firstcol, i == 0, x, y, cx, cy, s,
// style | en, stdfont, false, false, 0, -1, 0, true);
Color fg = Black;
Color bg = Blend(Blue, White, 240);
w.DrawRect(x, y, cx, 1, Gray);
Font fnt(stdfont);
if(style & GD::READONLY)
{
bg = Blend(bg, SGray(), 40);
fg = Blend(fg, SGray(), 200);
}
gd->Paint(w, x, y + 1, cx, cy - 1, s, style, fg, bg, fnt.Bold(), false, 0, 0);
it.rcx = gd->real_size.cx;
it.rcy = gd->real_size.cy;
}
}
}
}
if(rx < sz.cx || chameleon)
{
int cx = sz.cx - rx + 1;
dword style = 0;
if(chameleon)
{
cx = max(10, cx);
style = GD::CHAMELEON;
}
display->PaintFixed(w, 0, 1, rx, 0, cx, fixed_height,
Value(""),
style, stdfont, false, false,
0, -1, 0,
true);
if(summary_row)
{
Color fg = Black;
Color bg = Blend(Blue, White, 240);
w.DrawRect(rx, y, cx, 1, Gray);
if(style & GD::READONLY)
{
bg = Blend(bg, SGray(), 40);
fg = Blend(fg, SGray(), 200);
}
display->Paint(w, rx, y + 1, cx, GD_HDR_HEIGHT - 1, Value(""), style, fg, bg, stdfont, false, 0, 0);
}
}
w.End();
}
//---------------------------------------------------------------------------------------
bool can_paint = firstCol >= 0 && firstRow >= 0;
r.Set(0, fixed_height, fixed_width, sz.cy);
if(can_paint && w.IsPainting(r))
{
LG(0, "Left header");
w.Clip(r);
y = vitems[total_rows - 1].nBottom(sby);
if(y < sz.cy)
w.DrawRect(Rect(0, y, fixed_width, sz.cy - summary_height), SColorPaper);
for(i = 0; i < fixed_cols; i++)
{
bool firstx = (i == !indicator);
bool indicator = (i == 0);
int id = hitems[i].id;
for(j = firstRow; j < total_rows; j++)
{
ItemRect& vi = vitems[j];
if(vi.hidden)
continue;
Item &it = GetItemSize(j, i, x, y, cx, cy, skip, false, true);
if(skip)
continue;
if(y >= rc.bottom)
break;
if(w.IsPainting(x, y, cx, cy))
{
GridDisplay * gd = it.display ? it.display : display;
dword style = vi.style;
if(i > 0) style &= ~GD::HIGHLIGHT;
if(chameleon)
style |= GD::CHAMELEON;
Font fnt(stdfont);
gd->PaintFixed(w, firstx, j == 0, x, y, cx, cy,
GetConvertedColumn(id, it.val),
style | en, IsNull(vi.hfnt) ? fnt : vi.hfnt,
indicator, false, 0, -1, 0, false);
it.rcx = gd->real_size.cx;
it.rcy = gd->real_size.cy;
}
}
if(summary_row)
{
j = 0;
cy = GD_HDR_HEIGHT;
y = sz.cy - cy;
if(w.IsPainting(x, y, cx, cy))
{
Item& it = summary[hitems[i].id];
GridDisplay * gd = it.display ? it.display : display;
dword style = vitems[j].style;
if(chameleon)
style |= GD::CHAMELEON;
// gd->PaintFixed(w, firstx, true, x, y, cx, cy,
// GetConvertedColumn(id, it.val),
// style | en, stdfont,
// false, false, 0, -1, 0, false);
//
Color fg = Black;
Color bg = Blend(Blue, White, 240);
w.DrawRect(x, y, cx, 1, Gray);
Font fnt(stdfont);
gd->Paint(w, x, y + 1, cx, cy - 1, GetConvertedColumn(id, it.val), style | en, fg, bg, fnt.Bold(), false, 0, 0);
}
}
}
w.End();
}
//---------------------------------------------------------------------------------------
// Draw the "active" (non-fixed) cells:
r.Set(fixed_width, fixed_height, sz.cx, sz.cy - summary_height);
if(can_paint && w.IsPainting(r))
{
LG(0, "Body");
w.Clip(r);
x = hitems[total_cols - 1].nRight(sbx);
y = vitems[total_rows - 1].nBottom(sby);
if(x < sz.cx) w.DrawRect(Rect(max(x, rc.left), max(fixed_height, rc.top), sz.cx, sz.cy), SColorPaper);
if(y < sz.cy) w.DrawRect(Rect(max(fixed_width, rc.left), max(y, rc.top), sz.cx, sz.cy), SColorPaper);
bool hasfocus = HasFocus() || holder.HasFocusDeep();
for(i = max(firstRow, fixed_rows); i < total_rows; i++)
{
ItemRect& vi = vitems[i];
if(vi.hidden) continue;
bool even = coloring_mode == 2 ? (i - vi.n - fixed_rows) & 1 : false;
for(j = max(firstCol, fixed_cols); j < total_cols; j++)
{
const ItemRect& hi = hitems[j];
if(hi.hidden)
continue;
Item &it = GetItemSize(i, j, x, y, cx, cy, skip);
if(skip)
continue;
if(y >= rc.bottom)
goto end_paint;
if(x >= rc.right)
break;
if(!w.IsPainting(0, y, sz.cx, cy))
break;
if(w.IsPainting(x, y, cx, cy))
{
bool iscur = draw_focus ? (i == curpos.y && j == curpos.x) : false;
if(coloring_mode == 1)
even = (j - hi.n - fixed_cols) & 1;
int id = hi.id;
dword style = en | (select_row ? vi.style : it.style) | hi.balign;
dword istyle = it.style;
if(hitems[j].wrap)
style |= GD::WRAP;
if(ctrlpos.y == i && edits[id].ctrl && edits[id].ctrl->IsShown())
style |= GD::NOTEXT;
if(it.ctrl)
style |= GD::NOTEXT;
if(coloring_mode > 0)
style |= (even ? GD::EVEN : GD::ODD);
if(hasfocus)
style |= GD::FOCUS;
if(IsValidCursor(anchor) && anchor != curpos) { // mouse selection in progress
Rect r(anchor, curpos);
r.Normalize();
r.SetSize(r.GetSize() + 1);
if(r.Contains(Point(j, i)))
style |= GD::SELECT;
}
Color cfg;
Color cbg;
Font fnt = StdFont();
GridDisplay* gd;
Value val = GetItemValue(it, id, hi, vi);
GetItemAttrs(it, val, i, j, vi, hi, style, gd, cfg, cbg, fnt);
Color fg = SColorText;
Color bg = SColorPaper;
bool custom = true;
if(style & GD::CURSOR)
{
if(style & GD::FOCUS)
{
fg = iscur ? Blend(bg_focus, Black, 230) : fg_focus;
bg = iscur ? Blend(bg_focus, White, 230) : bg_focus;
}
else
{
bg = Blend(SColorDisabled, bg);
}
custom = false;
}
else if(style & GD::LIVE)
{
fg = fg_live;
bg = bg_live;
custom = false;
}
else if(istyle & GD::FOUND)
{
fg = fg_found;
bg = bg_found;
custom = false;
}
else if(style & GD::SELECT)
{
fg = fg_select;
bg = bg_select;
custom = false;
}
else if(style & GD::EVEN)
{
fg = fg_even;
bg = bg_even;
}
else if(style & GD::ODD)
{
fg = fg_odd;
bg = bg_odd;
}
if(custom)
{
if(!IsNull(cfg)) fg = cfg;
if(!IsNull(cbg)) bg = cbg;
}
if(style & GD::READONLY)
{
bg = Blend(bg, SGray(), 40);
fg = Blend(fg, SGray(), 200);
}
gd->SetBgImage(vi.img);
gd->col = j - fixed_rows;
gd->row = i - fixed_cols;
gd->parent = this;
val = GetAttrTextVal(val);
gd->Paint(w, x, y, cx, cy,
val, style,
fg, bg, fnt, it.style & GD::FOUND, it.fs, it.fe);
it.rcx = gd->real_size.cx;
it.rcy = gd->real_size.cy;
if(vert_grid)
{
bool skip = false;
if(!draw_last_vert_line && j == total_cols - 1)
skip = true;
if(!skip)
w.DrawRect(x + cx - 1, y, 1, cy, fg_grid);
}
if(horz_grid)
{
bool skip = false;
if(!draw_last_horz_line && i == total_rows - 1)
skip = true;
if(!skip)
w.DrawRect(x, y + cy - 1, cx, 1, fg_grid);
}
if(iscur && draw_focus)
Upp::DrawFocus(w, x, y, cx, cy);
}
}
}
end_paint:
w.End();
lastCol = j - 1;
lastRow = i - 1;
}
if(moving_header && fixed_top_click && curSplitCol >= 0)
{
r.Set(fixed_width, 0, sz.cx, fixed_height);
w.Clip(r);
bool lastcol = curSplitCol == lastVisCol;
int cp = curSplitCol;
if(!lastcol)
while(++cp < total_cols && hitems[cp].hidden);
int cx = hitems[cp].nWidth() / 2;
int x = lastcol ? hitems[curSplitCol].nLeft(sbx) + cx
: hitems[curSplitCol].nRight(sbx) - 1;
DrawFatFrame(w, x, 0, cx, vitems[fixed_rows - 1].nBottom(), moving_allowed ? LtBlue : Red, 2);
w.End();
}
if(moving_header && fixed_left_click)
{
int dy = curSplitRow == lastVisRow ? -2 : -1;
int y = curSplitRow >= 0 ? vitems[curSplitRow].nBottom(sby) + dy : 0;
if(y >= fixed_height - 1)
DrawVertDragLine(w, y, hitems[fixed_cols - 1].nRight(), 0, moving_allowed ? LtBlue : Red);
}
if(moving_body)
{
int dy = curSplitRow == lastVisRow ? -2 : -1;
int y = curSplitRow >= 0 ? vitems[curSplitRow].nBottom(sby) + dy : 0;
if(y >= fixed_height - 1)
DrawVertDragLine(w, y, sz.cx, fixed_width - 1, LtBlue);
}
if(search_display && !search_string.IsEmpty())
{
Size tsz = GetTextSize(search_string, StdFont());
w.DrawRect(Rect(0, sz.cy - tsz.cy - 4, tsz.cx + 4, sz.cy), SRed);
w.DrawText(2, sz.cy - tsz.cy - 2, search_string, StdFont(), SYellow);
}
if(!can_paint)
w.DrawRect(Rect(0, total_cols > 1 ? fixed_height : 0, sz.cx, sz.cy), SColorPaper);
if(++paint_flag > 100)
paint_flag = 0;
LG(0, "---- Paint(%d).", paintcnt);
}
};

View file

@ -0,0 +1,258 @@
#include "GridCtrl.h"
namespace Upp {
void GridCtrl::Select(int n, int cnt /* = 1*/)
{
SelectCount(n + fixed_rows, cnt, true);
}
void GridCtrl::SelectCount(int i, int cnt, bool sel)
{
if(cnt <= 0)
return;
SelectRange(Point(fixed_cols, i), Point(total_cols - 1, i + cnt - 1), sel);
}
void GridCtrl::SelectRange(int from, int to, bool sel)
{
SelectRange(Point(fixed_cols, from), Point(total_cols - 1, to), sel);
}
void GridCtrl::ShiftSelect(int from, int to)
{
ShiftSelect(Point(fixed_cols, from), Point(total_cols - 1, to));
}
void GridCtrl::SelectRange(Point from, Point to, bool sel /* = true*/, bool fullrow /* = false*/)
{
Point f, t;
if(fullrow)
{
from.x = fixed_cols;
to.x = total_cols - 1;
}
if(from.y < to.y)
{
f = from;
t = to;
}
else
{
f = to;
t = from;
}
int ymin = f.y;
int ymax = t.y;
int xmin = f.x;
int xmax = t.x;
if(xmin > xmax)
{
int t = xmin;
xmin = xmax;
xmax = t;
}
for(int i = ymin; i <= ymax; i++)
{
ItemRect &ir = vitems[i];
int yid = ir.id;
bool is_row_selected = false;
bool do_refresh = false;
for(int j = fixed_cols; j < total_cols; j++)
{
int xid = hitems[j].id;
Item &it = items[yid][xid];
if(j >= xmin && j <= xmax)
{
if(it.IsSelect() != sel)
{
it.Select(sel);
do_refresh = true;
}
if(sel)
{
is_row_selected = true;
selected_items++;
}
else
selected_items--;
}
else if(it.IsSelect())
is_row_selected = true;
}
if(!ir.IsSelect())
{
if(is_row_selected)
selected_rows++;
}
else if(!is_row_selected)
selected_rows--;
ir.Select(is_row_selected);
if(do_refresh)
RefreshRow(i, false, false);
}
}
void GridCtrl::SelectInverse(int from, int to)
{
int nfrom = min(from, to);
int nto = max(from, to);
for(int i = nfrom ; i <= nto; i++)
{
vitems[i].Select(!vitems[i].IsSelect());
if(vitems[i].IsSelect())
selected_rows++;
else
selected_rows--;
RefreshRow(i, 0);
}
}
void GridCtrl::ShiftSelect(Point from, Point to)
{
Point f, t;
if(from.y < to.y)
{
f = from;
t = to;
}
else
{
f = to;
t = from;
}
if(select_row)
{
f.x = fixed_cols;
t.x = total_cols;
}
int ymin = f.y;
int ymax = t.y;
int xmin = f.x;
int xmax = t.x;
if(ymin == ymax && xmin > xmax)
{
int t = xmin;
xmin = xmax;
xmax = t;
}
selected_rows = 0;
selected_items = 0;
for(int i = fixed_rows; i < total_rows; i++)
{
ItemRect &ir = vitems[i];
int yid = ir.id;
bool is_row_selected = false;
bool do_refresh = false;
if((i >= ymin && i <= ymax))
{
for(int j = fixed_cols; j < total_cols; j++)
{
int xid = hitems[j].id;
bool s = true;
if(i == ymin && ymin == ymax)
s = (j >= xmin && j <= xmax);
else if(i == ymin) s = (j >= xmin);
else if(i == ymax) s = (j <= xmax);
if(items[yid][xid].IsSelect() != s)
{
items[yid][xid].Select(s);
do_refresh = true;
}
if(s)
{
is_row_selected = true;
selected_items++;
}
}
}
else
{
for(int j = fixed_cols; j < total_cols; j++)
if(items[yid][j].IsSelect())
{
items[yid][j].Select(false);
do_refresh = true;
}
}
if(is_row_selected)
selected_rows++;
ir.Select(is_row_selected);
if(do_refresh)
RefreshRow(i, false, false);
}
}
void GridCtrl::SelectRange(const Rect& r, bool sel /* = true*/, bool fullrow /* = false*/)
{
Rect rr = r.Normalized();
SelectRange(rr.TopLeft(), rr.BottomRight(), sel, fullrow);
}
bool GridCtrl::IsSelected(int n, bool relative)
{
//int id = vitems[n + (relative ? fixed_rows : 0)].id;
int id = n + (relative ? fixed_rows : 0);
return vitems[id].IsSelect() || vitems[id].IsCursor();
}
bool GridCtrl::IsSelected(int n, int m, bool relative)
{
int r = relative ? fixed_rows + n : n;
int c = relative ? fixed_cols + m : m;
Item &it = GetItem(r, c);
return it.IsSelect() || it.IsCursor();
}
bool GridCtrl::IsSelected()
{
return IsSelected(rowidx, false);
}
void GridCtrl::ClearSelection()
{
LG(0, "Cleared %d", selected_rows);
if(selected_rows > 0)
{
for(int i = fixed_rows; i < total_rows; i++)
{
vitems[i].Select(0);
for(int j = fixed_cols; j < total_cols; j++)
items[i][j].Select(0);
}
Refresh();
selected_rows = 0;
selected_items = 0;
}
}
};

View file

@ -4,25 +4,11 @@
extern FileSel& sSD();
static void sSetFolder(EditField *f)
{
if(!sSD().ExecuteSelectDir()) return;
*f <<= ~sSD();
}
void DirSel(EditField& f, FrameRight<Button>& b)
{
f.AddFrame(b);
b <<= callback1(&sSetFolder, &f);
b.SetImage(CtrlImg::smallright()).NoWantFocus();
}
String NormalizePathNN(const String& path)
{
return IsNull(path) ? path : NormalizePath(path);
}
#ifdef PLATFORM_WIN32
bool ExistProgram(String& bin, const char *dir, const char *file)
{

View file

@ -4,6 +4,24 @@
#define IMAGEFILE <ide/Common/common.iml>
#include <Draw/iml_source.h>
void DirSelect(Ctrl& t, Button& b)
{
b.SetImage(CtrlImg::Dir());
b << [&] {
String s = SelectDirectory();
if(s.GetCount())
t <<= s;
};
}
void DirSel(EditField& f, FrameRight<Button>& b)
{
b.Width(DPI(20));
f.InsertFrame(0, b);
f.InsertFrame(1, RightGapFrame());
DirSelect(f, b);
}
void IdeFileIcon0(bool dir, const String& filename, Image& img)
{
if(dir) return;
@ -233,13 +251,3 @@ void ShellOpenFolder(const String& dir)
);
#endif
}
void DirSelect(Ctrl& t, Button& b)
{
b.SetImage(CtrlImg::Dir());
b << [&] {
String s = SelectDirectory();
if(s.GetCount())
t <<= s;
};
}

View file

@ -27,8 +27,6 @@ FileSel& AnyPackageFs();
FileSel& BasedSourceFs();
FileSel& OutputFs();
void DirSelect(Ctrl& t, Button& b);
void ShellOpenFolder(const String& dir);
Image ImageOver(const Image& back, const Image& over);

View file

@ -306,6 +306,7 @@ void DlSpellerLangs(DropList& dl);
#include "Assist.h"
void DirSelect(Ctrl& t, Button& b);
void DirSel(EditField& f, FrameRight<Button>& b);
bool CopyFolder(const char *dst, const char *src, Progress *pi);
void RepoSyncDirs(const Vector<String>& working);