2020-03-24 04:38:20 +00:00
|
|
|
#include <QF/keys.h>
|
2020-04-04 05:32:54 +00:00
|
|
|
#include <string.h>
|
2020-06-21 14:15:17 +00:00
|
|
|
#include "ruamoko/qwaq/qwaq-app.h"
|
|
|
|
#include "ruamoko/qwaq/editor/editor.h"
|
|
|
|
#include "ruamoko/qwaq/ui/listener.h"
|
|
|
|
#include "ruamoko/qwaq/ui/scrollbar.h"
|
2020-03-22 13:03:34 +00:00
|
|
|
|
|
|
|
@implementation Editor
|
|
|
|
|
|
|
|
-initWithRect:(Rect) rect file:(string) filename
|
|
|
|
{
|
|
|
|
if (!(self = [super initWithRect: rect])) {
|
|
|
|
return nil;
|
|
|
|
}
|
2020-04-04 05:32:54 +00:00
|
|
|
self.filename = str_hold (filename);
|
2020-03-30 07:30:58 +00:00
|
|
|
buffer = [[EditBuffer withFile:filename] retain];
|
2020-03-22 13:03:34 +00:00
|
|
|
line_count = [buffer countLines: {0, [buffer textSize]}];
|
2020-03-30 07:30:58 +00:00
|
|
|
linebuffer = [[DrawBuffer buffer: { xlen, 1 }] retain];
|
2020-03-23 11:14:32 +00:00
|
|
|
growMode = gfGrowHi;
|
2020-03-26 08:28:38 +00:00
|
|
|
options = ofCanFocus | ofRelativeEvents;
|
2020-03-31 02:21:47 +00:00
|
|
|
[onViewScrolled addListener:self :@selector(onScroll:)];
|
2020-03-22 13:03:34 +00:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2020-03-30 13:02:58 +00:00
|
|
|
+(Editor *)withRect:(Rect)rect file:(string)filename
|
|
|
|
{
|
|
|
|
return [[[self alloc] initWithRect:rect file:filename] autorelease];
|
|
|
|
}
|
|
|
|
|
2020-03-30 07:30:58 +00:00
|
|
|
-(void)dealloc
|
|
|
|
{
|
2020-04-04 05:32:54 +00:00
|
|
|
str_free (filename);
|
2020-03-30 13:02:58 +00:00
|
|
|
[vScrollBar release];
|
2020-03-30 07:30:58 +00:00
|
|
|
[buffer release];
|
|
|
|
[linebuffer release];
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
2020-03-24 16:07:58 +00:00
|
|
|
-(string)filename
|
|
|
|
{
|
|
|
|
return filename;
|
|
|
|
}
|
|
|
|
|
2020-03-22 13:03:34 +00:00
|
|
|
-draw
|
|
|
|
{
|
2020-03-22 13:42:56 +00:00
|
|
|
[super draw];
|
2020-03-22 13:03:34 +00:00
|
|
|
unsigned lind = base_index;
|
|
|
|
int *lbuf = [linebuffer buffer];
|
|
|
|
for (int y = 0; y < ylen; y++) {
|
2020-03-31 02:21:47 +00:00
|
|
|
lind = [buffer formatLine:lind from:base.x into:lbuf width:xlen
|
2020-03-26 00:01:39 +00:00
|
|
|
highlight:selection colors: {color_palette[047],
|
|
|
|
color_palette[007]}];
|
2020-03-22 13:03:34 +00:00
|
|
|
[textContext blitFromBuffer: linebuffer to: {xpos, ypos + y}
|
|
|
|
from: [linebuffer rect]];
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2020-03-23 11:14:32 +00:00
|
|
|
-resize: (Extent) delta
|
|
|
|
{
|
|
|
|
[super resize: delta];
|
|
|
|
[linebuffer resizeTo: {xlen, 1}];
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2020-03-25 08:29:08 +00:00
|
|
|
static int handleEvent (Editor *self, qwaq_event_t *event)
|
2020-03-22 13:42:56 +00:00
|
|
|
{
|
|
|
|
if (event.what & qe_mouse) {
|
|
|
|
if (event.what == qe_mouseclick) {
|
|
|
|
if (event.mouse.buttons & (1 << 3)) {
|
|
|
|
[self scrollUp: 1];
|
2020-03-25 08:29:08 +00:00
|
|
|
return 1;
|
2020-03-22 13:42:56 +00:00
|
|
|
}
|
|
|
|
if (event.mouse.buttons & (1 << 4)) {
|
|
|
|
[self scrollDown: 1];
|
2020-03-25 08:29:08 +00:00
|
|
|
return 1;
|
2020-03-22 13:42:56 +00:00
|
|
|
}
|
|
|
|
if (event.mouse.buttons & (1 << 5)) {
|
|
|
|
[self scrollLeft: 1];
|
2020-03-25 08:29:08 +00:00
|
|
|
return 1;
|
2020-03-22 13:42:56 +00:00
|
|
|
}
|
|
|
|
if (event.mouse.buttons & (1 << 6)) {
|
|
|
|
[self scrollRight: 1];
|
2020-03-25 08:29:08 +00:00
|
|
|
return 1;
|
2020-03-22 13:42:56 +00:00
|
|
|
}
|
|
|
|
}
|
2020-03-24 04:38:20 +00:00
|
|
|
} else if (event.what == qe_keydown) {
|
|
|
|
switch (event.key.code) {
|
|
|
|
case QFK_PAGEUP:
|
2020-03-25 08:29:08 +00:00
|
|
|
[self scrollUp: self.ylen];
|
|
|
|
return 1;
|
2020-03-24 04:38:20 +00:00
|
|
|
case QFK_PAGEDOWN:
|
2020-03-25 08:29:08 +00:00
|
|
|
[self scrollDown: self.ylen];
|
|
|
|
return 1;
|
2020-03-24 04:38:20 +00:00
|
|
|
}
|
2020-03-22 13:42:56 +00:00
|
|
|
}
|
2020-03-25 08:29:08 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
-handleEvent:(qwaq_event_t *) event
|
|
|
|
{
|
2020-03-26 02:04:57 +00:00
|
|
|
[super handleEvent: event];
|
|
|
|
|
2020-03-25 08:29:08 +00:00
|
|
|
if (handleEvent (self, event)) {
|
|
|
|
event.what = qe_none;
|
|
|
|
}
|
2020-03-22 13:42:56 +00:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
-scrollUp:(unsigned) count
|
|
|
|
{
|
|
|
|
if (count == 1) {
|
|
|
|
base_index = [buffer prevLine: base_index];
|
|
|
|
} else {
|
|
|
|
base_index = [buffer prevLine: base_index :count];
|
|
|
|
}
|
|
|
|
[self redraw];
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
-scrollDown:(unsigned) count
|
|
|
|
{
|
|
|
|
if (count == 1) {
|
|
|
|
base_index = [buffer nextLine: base_index];
|
|
|
|
} else {
|
|
|
|
base_index = [buffer nextLine: base_index :count];
|
|
|
|
}
|
|
|
|
[self redraw];
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
-scrollLeft:(unsigned) count
|
|
|
|
{
|
2020-03-31 02:21:47 +00:00
|
|
|
if (base.x > count) {
|
|
|
|
base.x -= count;
|
2020-03-22 13:42:56 +00:00
|
|
|
} else {
|
2020-03-31 02:21:47 +00:00
|
|
|
base.x = 0;
|
2020-03-22 13:42:56 +00:00
|
|
|
}
|
|
|
|
[self redraw];
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
-scrollRight:(unsigned) count
|
|
|
|
{
|
2020-03-31 02:21:47 +00:00
|
|
|
if (1024 - base.x > count) {
|
|
|
|
base.x += count;
|
2020-03-22 13:42:56 +00:00
|
|
|
} else {
|
2020-03-31 02:21:47 +00:00
|
|
|
base.x = 1024;
|
2020-03-22 13:42:56 +00:00
|
|
|
}
|
|
|
|
[self redraw];
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2020-03-30 13:50:29 +00:00
|
|
|
-scrollTo:(unsigned)target
|
|
|
|
{
|
2020-03-31 02:21:47 +00:00
|
|
|
if (target > base.y) {
|
|
|
|
base_index = [buffer nextLine:base_index :target - base.y];
|
|
|
|
} else if (target < base.y) {
|
|
|
|
base_index = [buffer prevLine:base_index :base.y - target];
|
2020-03-30 13:50:29 +00:00
|
|
|
}
|
2020-03-31 02:21:47 +00:00
|
|
|
base.y = target;
|
2020-03-30 13:50:29 +00:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
-(void)onScroll:(id)sender
|
|
|
|
{
|
2020-03-31 02:21:47 +00:00
|
|
|
base.x = scroll.x;
|
|
|
|
[self scrollTo:scroll.y];
|
|
|
|
}
|
|
|
|
|
|
|
|
-setVerticalScrollBar:(ScrollBar *)scrollbar
|
|
|
|
{
|
|
|
|
[super setVerticalScrollBar:scrollbar];
|
|
|
|
[vScrollBar setRange:line_count];
|
|
|
|
[vScrollBar setPageStep: ylen];
|
|
|
|
return self;
|
2020-03-30 13:50:29 +00:00
|
|
|
}
|
|
|
|
|
2020-03-24 23:28:12 +00:00
|
|
|
-recenter:(int) force
|
|
|
|
{
|
|
|
|
if (!force) {
|
2020-03-31 02:21:47 +00:00
|
|
|
if (cursor.y >= base.y && cursor.y - base.y < ylen) {
|
2020-03-24 23:28:12 +00:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
unsigned target;
|
|
|
|
if (cursor.y < ylen / 2) {
|
|
|
|
target = 0;
|
|
|
|
} else {
|
|
|
|
target = cursor.y - ylen / 2;
|
|
|
|
}
|
2020-03-30 13:50:29 +00:00
|
|
|
[self scrollTo:target];
|
2020-03-24 23:28:12 +00:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
-gotoLine:(unsigned) line
|
|
|
|
{
|
|
|
|
if (line > cursor.y) {
|
|
|
|
line_index = [buffer nextLine:line_index :line - cursor.y];
|
|
|
|
} else if (line < cursor.y) {
|
|
|
|
line_index = [buffer prevLine:line_index :cursor.y - line];
|
|
|
|
}
|
|
|
|
cursor.y = line;
|
|
|
|
[self recenter: 0];
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
-highlightLine
|
|
|
|
{
|
|
|
|
selection.start = line_index;
|
|
|
|
selection.length = [buffer nextLine: line_index] - line_index;
|
|
|
|
if (!selection.length) {
|
|
|
|
selection.length = [buffer getEOL: line_index] - line_index;
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2020-03-25 08:29:08 +00:00
|
|
|
-(string)getWordAt:(Point) pos
|
|
|
|
{
|
|
|
|
if (pos.x < 0 || pos.y < 0 || pos.x >= xlen || pos.y >= ylen) {
|
|
|
|
return nil;
|
|
|
|
}
|
2020-03-31 02:21:47 +00:00
|
|
|
pos.x += base.x;
|
2020-03-25 08:29:08 +00:00
|
|
|
unsigned lind = [buffer nextLine:base_index :pos.y];
|
|
|
|
unsigned cind = [buffer charPtr:lind at:pos.x];
|
|
|
|
eb_sel_t word = [buffer getWord: cind];
|
|
|
|
return [buffer readString:word];
|
|
|
|
}
|
|
|
|
|
2020-03-22 13:03:34 +00:00
|
|
|
@end
|